1 /*
2 
3  gg_wkb.c -- Gaia common support for WKB encoded geometries
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 <float.h>
50 #include <string.h>
51 
52 #if defined(_WIN32) && !defined(__MINGW32__)
53 #include "config-msvc.h"
54 #else
55 #include "config.h"
56 #endif
57 
58 #include <spatialite/sqlite.h>
59 
60 #include <spatialite/gaiageo.h>
61 #include <spatialite/geopackage.h>
62 
63 static void
ParseWkbPoint(gaiaGeomCollPtr geo)64 ParseWkbPoint (gaiaGeomCollPtr geo)
65 {
66 /* decodes a POINT from WKB */
67     double x;
68     double y;
69     if (geo->size < geo->offset + 16)
70 	return;
71     x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
72     y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
73 		      geo->endian_arch);
74     geo->offset += 16;
75     gaiaAddPointToGeomColl (geo, x, y);
76 }
77 
78 static void
ParseWkbPointZ(gaiaGeomCollPtr geo)79 ParseWkbPointZ (gaiaGeomCollPtr geo)
80 {
81 /* decodes a POINTZ from WKB */
82     double x;
83     double y;
84     double z;
85     if (geo->size < geo->offset + 24)
86 	return;
87     x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
88     y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
89 		      geo->endian_arch);
90     z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
91 		      geo->endian_arch);
92     geo->offset += 24;
93     gaiaAddPointToGeomCollXYZ (geo, x, y, z);
94 }
95 
96 static void
ParseWkbPointM(gaiaGeomCollPtr geo)97 ParseWkbPointM (gaiaGeomCollPtr geo)
98 {
99 /* decodes a POINTM from WKB */
100     double x;
101     double y;
102     double m;
103     if (geo->size < geo->offset + 24)
104 	return;
105     x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
106     y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
107 		      geo->endian_arch);
108     m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
109 		      geo->endian_arch);
110     geo->offset += 24;
111     gaiaAddPointToGeomCollXYM (geo, x, y, m);
112 }
113 
114 static void
ParseWkbPointZM(gaiaGeomCollPtr geo)115 ParseWkbPointZM (gaiaGeomCollPtr geo)
116 {
117 /* decodes a POINTZM from WKB */
118     double x;
119     double y;
120     double z;
121     double m;
122     if (geo->size < geo->offset + 32)
123 	return;
124     x = gaiaImport64 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
125     y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
126 		      geo->endian_arch);
127     z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
128 		      geo->endian_arch);
129     m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian,
130 		      geo->endian_arch);
131     geo->offset += 32;
132     gaiaAddPointToGeomCollXYZM (geo, x, y, z, m);
133 }
134 
135 static void
ParseWkbLine(gaiaGeomCollPtr geo)136 ParseWkbLine (gaiaGeomCollPtr geo)
137 {
138 /* decodes a LINESTRING from WKB */
139     int points;
140     int iv;
141     double x;
142     double y;
143     gaiaLinestringPtr line;
144     if (geo->size < geo->offset + 4)
145 	return;
146     points =
147 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
148     geo->offset += 4;
149     if (geo->size < geo->offset + (16 * points))
150 	return;
151     line = gaiaAddLinestringToGeomColl (geo, points);
152     for (iv = 0; iv < points; iv++)
153       {
154 	  x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
155 			    geo->endian_arch);
156 	  y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
157 			    geo->endian_arch);
158 	  gaiaSetPoint (line->Coords, iv, x, y);
159 	  geo->offset += 16;
160       }
161 }
162 
163 static void
ParseWkbLineZ(gaiaGeomCollPtr geo)164 ParseWkbLineZ (gaiaGeomCollPtr geo)
165 {
166 /* decodes a LINESTRINGZ from WKB */
167     int points;
168     int iv;
169     double x;
170     double y;
171     double z;
172     gaiaLinestringPtr line;
173     if (geo->size < geo->offset + 4)
174 	return;
175     points =
176 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
177     geo->offset += 4;
178     if (geo->size < geo->offset + (24 * points))
179 	return;
180     line = gaiaAddLinestringToGeomColl (geo, points);
181     for (iv = 0; iv < points; iv++)
182       {
183 	  x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
184 			    geo->endian_arch);
185 	  y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
186 			    geo->endian_arch);
187 	  z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
188 			    geo->endian_arch);
189 	  gaiaSetPointXYZ (line->Coords, iv, x, y, z);
190 	  geo->offset += 24;
191       }
192 }
193 
194 static void
ParseWkbLineM(gaiaGeomCollPtr geo)195 ParseWkbLineM (gaiaGeomCollPtr geo)
196 {
197 /* decodes a LINESTRINGM from WKB */
198     int points;
199     int iv;
200     double x;
201     double y;
202     double m;
203     gaiaLinestringPtr line;
204     if (geo->size < geo->offset + 4)
205 	return;
206     points =
207 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
208     geo->offset += 4;
209     if (geo->size < geo->offset + (24 * points))
210 	return;
211     line = gaiaAddLinestringToGeomColl (geo, points);
212     for (iv = 0; iv < points; iv++)
213       {
214 	  x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
215 			    geo->endian_arch);
216 	  y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
217 			    geo->endian_arch);
218 	  m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
219 			    geo->endian_arch);
220 	  gaiaSetPointXYM (line->Coords, iv, x, y, m);
221 	  geo->offset += 24;
222       }
223 }
224 
225 static void
ParseWkbLineZM(gaiaGeomCollPtr geo)226 ParseWkbLineZM (gaiaGeomCollPtr geo)
227 {
228 /* decodes a LINESTRINGZM from WKB */
229     int points;
230     int iv;
231     double x;
232     double y;
233     double z;
234     double m;
235     gaiaLinestringPtr line;
236     if (geo->size < geo->offset + 4)
237 	return;
238     points =
239 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
240     geo->offset += 4;
241     if (geo->size < geo->offset + (32 * points))
242 	return;
243     line = gaiaAddLinestringToGeomColl (geo, points);
244     for (iv = 0; iv < points; iv++)
245       {
246 	  x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
247 			    geo->endian_arch);
248 	  y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
249 			    geo->endian_arch);
250 	  z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
251 			    geo->endian_arch);
252 	  m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian,
253 			    geo->endian_arch);
254 	  gaiaSetPointXYZM (line->Coords, iv, x, y, z, m);
255 	  geo->offset += 32;
256       }
257 }
258 
259 static void
ParseWkbPolygon(gaiaGeomCollPtr geo)260 ParseWkbPolygon (gaiaGeomCollPtr geo)
261 {
262 /* decodes a POLYGON from WKB */
263     int rings;
264     int nverts;
265     int iv;
266     int ib;
267     double x;
268     double y;
269     gaiaPolygonPtr polyg = NULL;
270     gaiaRingPtr ring;
271     if (geo->size < geo->offset + 4)
272 	return;
273     rings =
274 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
275     geo->offset += 4;
276     for (ib = 0; ib < rings; ib++)
277       {
278 	  if (geo->size < geo->offset + 4)
279 	      return;
280 	  nverts =
281 	      gaiaImport32 (geo->blob + geo->offset, geo->endian,
282 			    geo->endian_arch);
283 	  geo->offset += 4;
284 	  if (geo->size < geo->offset + (16 * nverts))
285 	      return;
286 	  if (ib == 0)
287 	    {
288 		polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
289 		ring = polyg->Exterior;
290 	    }
291 	  else
292 	      ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
293 	  for (iv = 0; iv < nverts; iv++)
294 	    {
295 		x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
296 				  geo->endian_arch);
297 		y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
298 				  geo->endian_arch);
299 		geo->offset += 16;
300 		gaiaSetPoint (ring->Coords, iv, x, y);
301 	    }
302       }
303 }
304 
305 static void
ParseWkbPolygonZ(gaiaGeomCollPtr geo)306 ParseWkbPolygonZ (gaiaGeomCollPtr geo)
307 {
308 /* decodes a POLYGONZ from WKB */
309     int rings;
310     int nverts;
311     int iv;
312     int ib;
313     double x;
314     double y;
315     double z;
316     gaiaPolygonPtr polyg = NULL;
317     gaiaRingPtr ring;
318     if (geo->size < geo->offset + 4)
319 	return;
320     rings =
321 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
322     geo->offset += 4;
323     for (ib = 0; ib < rings; ib++)
324       {
325 	  if (geo->size < geo->offset + 4)
326 	      return;
327 	  nverts =
328 	      gaiaImport32 (geo->blob + geo->offset, geo->endian,
329 			    geo->endian_arch);
330 	  geo->offset += 4;
331 	  if (geo->size < geo->offset + (24 * nverts))
332 	      return;
333 	  if (ib == 0)
334 	    {
335 		polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
336 		ring = polyg->Exterior;
337 	    }
338 	  else
339 	      ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
340 	  for (iv = 0; iv < nverts; iv++)
341 	    {
342 		x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
343 				  geo->endian_arch);
344 		y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
345 				  geo->endian_arch);
346 		z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
347 				  geo->endian_arch);
348 		geo->offset += 24;
349 		gaiaSetPointXYZ (ring->Coords, iv, x, y, z);
350 	    }
351       }
352 }
353 
354 static void
ParseWkbPolygonM(gaiaGeomCollPtr geo)355 ParseWkbPolygonM (gaiaGeomCollPtr geo)
356 {
357 /* decodes a POLYGONM from WKB */
358     int rings;
359     int nverts;
360     int iv;
361     int ib;
362     double x;
363     double y;
364     double m;
365     gaiaPolygonPtr polyg = NULL;
366     gaiaRingPtr ring;
367     if (geo->size < geo->offset + 4)
368 	return;
369     rings =
370 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
371     geo->offset += 4;
372     for (ib = 0; ib < rings; ib++)
373       {
374 	  if (geo->size < geo->offset + 4)
375 	      return;
376 	  nverts =
377 	      gaiaImport32 (geo->blob + geo->offset, geo->endian,
378 			    geo->endian_arch);
379 	  geo->offset += 4;
380 	  if (geo->size < geo->offset + (24 * nverts))
381 	      return;
382 	  if (ib == 0)
383 	    {
384 		polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
385 		ring = polyg->Exterior;
386 	    }
387 	  else
388 	      ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
389 	  for (iv = 0; iv < nverts; iv++)
390 	    {
391 		x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
392 				  geo->endian_arch);
393 		y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
394 				  geo->endian_arch);
395 		m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
396 				  geo->endian_arch);
397 		geo->offset += 24;
398 		gaiaSetPointXYM (ring->Coords, iv, x, y, m);
399 	    }
400       }
401 }
402 
403 static void
ParseWkbPolygonZM(gaiaGeomCollPtr geo)404 ParseWkbPolygonZM (gaiaGeomCollPtr geo)
405 {
406 /* decodes a POLYGONZM from WKB */
407     int rings;
408     int nverts;
409     int iv;
410     int ib;
411     double x;
412     double y;
413     double z;
414     double m;
415     gaiaPolygonPtr polyg = NULL;
416     gaiaRingPtr ring;
417     if (geo->size < geo->offset + 4)
418 	return;
419     rings =
420 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
421     geo->offset += 4;
422     for (ib = 0; ib < rings; ib++)
423       {
424 	  if (geo->size < geo->offset + 4)
425 	      return;
426 	  nverts =
427 	      gaiaImport32 (geo->blob + geo->offset, geo->endian,
428 			    geo->endian_arch);
429 	  geo->offset += 4;
430 	  if (geo->size < geo->offset + (32 * nverts))
431 	      return;
432 	  if (ib == 0)
433 	    {
434 		polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
435 		ring = polyg->Exterior;
436 	    }
437 	  else
438 	      ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
439 	  for (iv = 0; iv < nverts; iv++)
440 	    {
441 		x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
442 				  geo->endian_arch);
443 		y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
444 				  geo->endian_arch);
445 		z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
446 				  geo->endian_arch);
447 		m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian,
448 				  geo->endian_arch);
449 		geo->offset += 32;
450 		gaiaSetPointXYZM (ring->Coords, iv, x, y, z, m);
451 	    }
452       }
453 }
454 
455 static void
ParseCompressedWkbLine(gaiaGeomCollPtr geo)456 ParseCompressedWkbLine (gaiaGeomCollPtr geo)
457 {
458 /* decodes a COMPRESSED LINESTRING from WKB */
459     int points;
460     int iv;
461     double x;
462     double y;
463     double last_x = 0.0;
464     double last_y = 0.0;
465     float fx;
466     float fy;
467     gaiaLinestringPtr line;
468     if (geo->size < geo->offset + 4)
469 	return;
470     points =
471 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
472     geo->offset += 4;
473     if (geo->size < geo->offset + (8 * points) + 16)
474 	return;
475     line = gaiaAddLinestringToGeomColl (geo, points);
476     for (iv = 0; iv < points; iv++)
477       {
478 	  if (iv == 0 || iv == (points - 1))
479 	    {
480 		/* first and last vertices are uncompressed */
481 		x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
482 				  geo->endian_arch);
483 		y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
484 				  geo->endian_arch);
485 		geo->offset += 16;
486 	    }
487 	  else
488 	    {
489 		/* any other intermediate vertex is compressed */
490 		fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
491 				    geo->endian_arch);
492 		fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian,
493 				    geo->endian_arch);
494 		x = last_x + fx;
495 		y = last_y + fy;
496 		geo->offset += 8;
497 	    }
498 	  gaiaSetPoint (line->Coords, iv, x, y);
499 	  last_x = x;
500 	  last_y = y;
501       }
502 }
503 
504 static void
ParseCompressedWkbLineZ(gaiaGeomCollPtr geo)505 ParseCompressedWkbLineZ (gaiaGeomCollPtr geo)
506 {
507 /* decodes a COMPRESSED LINESTRINGZ from WKB */
508     int points;
509     int iv;
510     double x;
511     double y;
512     double z;
513     double last_x = 0.0;
514     double last_y = 0.0;
515     double last_z = 0.0;
516     float fx;
517     float fy;
518     float fz;
519     gaiaLinestringPtr line;
520     if (geo->size < geo->offset + 4)
521 	return;
522     points =
523 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
524     geo->offset += 4;
525     if (geo->size < geo->offset + (12 * points) + 24)
526 	return;
527     line = gaiaAddLinestringToGeomColl (geo, points);
528     for (iv = 0; iv < points; iv++)
529       {
530 	  if (iv == 0 || iv == (points - 1))
531 	    {
532 		/* first and last vertices are uncompressed */
533 		x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
534 				  geo->endian_arch);
535 		y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
536 				  geo->endian_arch);
537 		z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
538 				  geo->endian_arch);
539 		geo->offset += 24;
540 	    }
541 	  else
542 	    {
543 		/* any other intermediate vertex is compressed */
544 		fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
545 				    geo->endian_arch);
546 		fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian,
547 				    geo->endian_arch);
548 		fz = gaiaImportF32 (geo->blob + (geo->offset + 8), geo->endian,
549 				    geo->endian_arch);
550 		x = last_x + fx;
551 		y = last_y + fy;
552 		z = last_z + fz;
553 		geo->offset += 12;
554 	    }
555 	  gaiaSetPointXYZ (line->Coords, iv, x, y, z);
556 	  last_x = x;
557 	  last_y = y;
558 	  last_z = z;
559       }
560 }
561 
562 static void
ParseCompressedWkbLineM(gaiaGeomCollPtr geo)563 ParseCompressedWkbLineM (gaiaGeomCollPtr geo)
564 {
565 /* decodes a COMPRESSED LINESTRINGM from WKB */
566     int points;
567     int iv;
568     double x;
569     double y;
570     double m;
571     double last_x = 0.0;
572     double last_y = 0.0;
573     float fx;
574     float fy;
575     gaiaLinestringPtr line;
576     if (geo->size < geo->offset + 4)
577 	return;
578     points =
579 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
580     geo->offset += 4;
581     if (geo->size < geo->offset + (16 * points) + 16)
582 	return;
583     line = gaiaAddLinestringToGeomColl (geo, points);
584     for (iv = 0; iv < points; iv++)
585       {
586 	  if (iv == 0 || iv == (points - 1))
587 	    {
588 		/* first and last vertices are uncompressed */
589 		x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
590 				  geo->endian_arch);
591 		y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
592 				  geo->endian_arch);
593 		m = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
594 				  geo->endian_arch);
595 		geo->offset += 24;
596 	    }
597 	  else
598 	    {
599 		/* any other intermediate vertex is compressed */
600 		fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
601 				    geo->endian_arch);
602 		fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian,
603 				    geo->endian_arch);
604 		m = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
605 				  geo->endian_arch);
606 		x = last_x + fx;
607 		y = last_y + fy;
608 		geo->offset += 16;
609 	    }
610 	  gaiaSetPointXYM (line->Coords, iv, x, y, m);
611 	  last_x = x;
612 	  last_y = y;
613       }
614 }
615 
616 static void
ParseCompressedWkbLineZM(gaiaGeomCollPtr geo)617 ParseCompressedWkbLineZM (gaiaGeomCollPtr geo)
618 {
619 /* decodes a COMPRESSED LINESTRINGZM from WKB */
620     int points;
621     int iv;
622     double x;
623     double y;
624     double z;
625     double m;
626     double last_x = 0.0;
627     double last_y = 0.0;
628     double last_z = 0.0;
629     float fx;
630     float fy;
631     float fz;
632     gaiaLinestringPtr line;
633     if (geo->size < geo->offset + 4)
634 	return;
635     points =
636 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
637     geo->offset += 4;
638     if (geo->size < geo->offset + (20 * points) + 24)
639 	return;
640     line = gaiaAddLinestringToGeomColl (geo, points);
641     for (iv = 0; iv < points; iv++)
642       {
643 	  if (iv == 0 || iv == (points - 1))
644 	    {
645 		/* first and last vertices are uncompressed */
646 		x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
647 				  geo->endian_arch);
648 		y = gaiaImport64 (geo->blob + (geo->offset + 8), geo->endian,
649 				  geo->endian_arch);
650 		z = gaiaImport64 (geo->blob + (geo->offset + 16), geo->endian,
651 				  geo->endian_arch);
652 		m = gaiaImport64 (geo->blob + (geo->offset + 24), geo->endian,
653 				  geo->endian_arch);
654 		geo->offset += 32;
655 	    }
656 	  else
657 	    {
658 		/* any other intermediate vertex is compressed */
659 		fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
660 				    geo->endian_arch);
661 		fy = gaiaImportF32 (geo->blob + (geo->offset + 4), geo->endian,
662 				    geo->endian_arch);
663 		fz = gaiaImportF32 (geo->blob + (geo->offset + 8), geo->endian,
664 				    geo->endian_arch);
665 		m = gaiaImport64 (geo->blob + (geo->offset + 12), geo->endian,
666 				  geo->endian_arch);
667 		x = last_x + fx;
668 		y = last_y + fy;
669 		z = last_z + fz;
670 		geo->offset += 20;
671 	    }
672 	  gaiaSetPointXYZM (line->Coords, iv, x, y, z, m);
673 	  last_x = x;
674 	  last_y = y;
675 	  last_z = z;
676       }
677 }
678 
679 static void
ParseCompressedWkbPolygon(gaiaGeomCollPtr geo)680 ParseCompressedWkbPolygon (gaiaGeomCollPtr geo)
681 {
682 /* decodes a COMPRESSED POLYGON from WKB */
683     int rings;
684     int nverts;
685     int iv;
686     int ib;
687     double x;
688     double y;
689     double last_x = 0.0;
690     double last_y = 0.0;
691     float fx;
692     float fy;
693     gaiaPolygonPtr polyg = NULL;
694     gaiaRingPtr ring;
695     if (geo->size < geo->offset + 4)
696 	return;
697     rings =
698 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
699     geo->offset += 4;
700     for (ib = 0; ib < rings; ib++)
701       {
702 	  if (geo->size < geo->offset + 4)
703 	      return;
704 	  nverts =
705 	      gaiaImport32 (geo->blob + geo->offset, geo->endian,
706 			    geo->endian_arch);
707 	  geo->offset += 4;
708 	  if (geo->size < geo->offset + (8 * nverts) + 16)
709 	      return;
710 	  if (ib == 0)
711 	    {
712 		polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
713 		ring = polyg->Exterior;
714 	    }
715 	  else
716 	      ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
717 	  for (iv = 0; iv < nverts; iv++)
718 	    {
719 		if (iv == 0 || iv == (nverts - 1))
720 		  {
721 		      /* first and last vertices are uncompressed */
722 		      x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
723 					geo->endian_arch);
724 		      y = gaiaImport64 (geo->blob + (geo->offset + 8),
725 					geo->endian, geo->endian_arch);
726 		      geo->offset += 16;
727 		  }
728 		else
729 		  {
730 		      /* any other intermediate vertex is compressed */
731 		      fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
732 					  geo->endian_arch);
733 		      fy = gaiaImportF32 (geo->blob + (geo->offset + 4),
734 					  geo->endian, geo->endian_arch);
735 		      x = last_x + fx;
736 		      y = last_y + fy;
737 		      geo->offset += 8;
738 		  }
739 		gaiaSetPoint (ring->Coords, iv, x, y);
740 		last_x = x;
741 		last_y = y;
742 	    }
743       }
744 }
745 
746 static void
ParseCompressedWkbPolygonZ(gaiaGeomCollPtr geo)747 ParseCompressedWkbPolygonZ (gaiaGeomCollPtr geo)
748 {
749 /* decodes a COMPRESSED POLYGONZ from WKB */
750     int rings;
751     int nverts;
752     int iv;
753     int ib;
754     double x;
755     double y;
756     double z;
757     double last_x = 0.0;
758     double last_y = 0.0;
759     double last_z = 0.0;
760     float fx;
761     float fy;
762     float fz;
763     gaiaPolygonPtr polyg = NULL;
764     gaiaRingPtr ring;
765     if (geo->size < geo->offset + 4)
766 	return;
767     rings =
768 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
769     geo->offset += 4;
770     for (ib = 0; ib < rings; ib++)
771       {
772 	  if (geo->size < geo->offset + 4)
773 	      return;
774 	  nverts =
775 	      gaiaImport32 (geo->blob + geo->offset, geo->endian,
776 			    geo->endian_arch);
777 	  geo->offset += 4;
778 	  if (geo->size < geo->offset + (12 * nverts) + 24)
779 	      return;
780 	  if (ib == 0)
781 	    {
782 		polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
783 		ring = polyg->Exterior;
784 	    }
785 	  else
786 	      ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
787 	  for (iv = 0; iv < nverts; iv++)
788 	    {
789 		if (iv == 0 || iv == (nverts - 1))
790 		  {
791 		      /* first and last vertices are uncompressed */
792 		      x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
793 					geo->endian_arch);
794 		      y = gaiaImport64 (geo->blob + (geo->offset + 8),
795 					geo->endian, geo->endian_arch);
796 		      z = gaiaImport64 (geo->blob + (geo->offset + 16),
797 					geo->endian, geo->endian_arch);
798 		      geo->offset += 24;
799 		  }
800 		else
801 		  {
802 		      /* any other intermediate vertex is compressed */
803 		      fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
804 					  geo->endian_arch);
805 		      fy = gaiaImportF32 (geo->blob + (geo->offset + 4),
806 					  geo->endian, geo->endian_arch);
807 		      fz = gaiaImportF32 (geo->blob + (geo->offset + 8),
808 					  geo->endian, geo->endian_arch);
809 		      x = last_x + fx;
810 		      y = last_y + fy;
811 		      z = last_z + fz;
812 		      geo->offset += 12;
813 		  }
814 		gaiaSetPointXYZ (ring->Coords, iv, x, y, z);
815 		last_x = x;
816 		last_y = y;
817 		last_z = z;
818 	    }
819       }
820 }
821 
822 static void
ParseCompressedWkbPolygonM(gaiaGeomCollPtr geo)823 ParseCompressedWkbPolygonM (gaiaGeomCollPtr geo)
824 {
825 /* decodes a COMPRESSED POLYGONM from WKB */
826     int rings;
827     int nverts;
828     int iv;
829     int ib;
830     double x;
831     double y;
832     double m;
833     double last_x = 0.0;
834     double last_y = 0.0;
835     float fx;
836     float fy;
837     gaiaPolygonPtr polyg = NULL;
838     gaiaRingPtr ring;
839     if (geo->size < geo->offset + 4)
840 	return;
841     rings =
842 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
843     geo->offset += 4;
844     for (ib = 0; ib < rings; ib++)
845       {
846 	  if (geo->size < geo->offset + 4)
847 	      return;
848 	  nverts =
849 	      gaiaImport32 (geo->blob + geo->offset, geo->endian,
850 			    geo->endian_arch);
851 	  geo->offset += 4;
852 	  if (geo->size < geo->offset + (16 * nverts) + 16)
853 	      return;
854 	  if (ib == 0)
855 	    {
856 		polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
857 		ring = polyg->Exterior;
858 	    }
859 	  else
860 	      ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
861 	  for (iv = 0; iv < nverts; iv++)
862 	    {
863 		if (iv == 0 || iv == (nverts - 1))
864 		  {
865 		      /* first and last vertices are uncompressed */
866 		      x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
867 					geo->endian_arch);
868 		      y = gaiaImport64 (geo->blob + (geo->offset + 8),
869 					geo->endian, geo->endian_arch);
870 		      m = gaiaImport64 (geo->blob + (geo->offset + 16),
871 					geo->endian, geo->endian_arch);
872 		      geo->offset += 24;
873 		  }
874 		else
875 		  {
876 		      /* any other intermediate vertex is compressed */
877 		      fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
878 					  geo->endian_arch);
879 		      fy = gaiaImportF32 (geo->blob + (geo->offset + 4),
880 					  geo->endian, geo->endian_arch);
881 		      m = gaiaImport64 (geo->blob + (geo->offset + 8),
882 					geo->endian, geo->endian_arch);
883 		      x = last_x + fx;
884 		      y = last_y + fy;
885 		      geo->offset += 16;
886 		  }
887 		gaiaSetPointXYM (ring->Coords, iv, x, y, m);
888 		last_x = x;
889 		last_y = y;
890 	    }
891       }
892 }
893 
894 static void
ParseCompressedWkbPolygonZM(gaiaGeomCollPtr geo)895 ParseCompressedWkbPolygonZM (gaiaGeomCollPtr geo)
896 {
897 /* decodes a COMPRESSED POLYGONZM from WKB */
898     int rings;
899     int nverts;
900     int iv;
901     int ib;
902     double x;
903     double y;
904     double z;
905     double m;
906     double last_x = 0.0;
907     double last_y = 0.0;
908     double last_z = 0.0;
909     float fx;
910     float fy;
911     float fz;
912     gaiaPolygonPtr polyg = NULL;
913     gaiaRingPtr ring;
914     if (geo->size < geo->offset + 4)
915 	return;
916     rings =
917 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
918     geo->offset += 4;
919     for (ib = 0; ib < rings; ib++)
920       {
921 	  if (geo->size < geo->offset + 4)
922 	      return;
923 	  nverts =
924 	      gaiaImport32 (geo->blob + geo->offset, geo->endian,
925 			    geo->endian_arch);
926 	  geo->offset += 4;
927 	  if (geo->size < geo->offset + (20 * nverts) + 24)
928 	      return;
929 	  if (ib == 0)
930 	    {
931 		polyg = gaiaAddPolygonToGeomColl (geo, nverts, rings - 1);
932 		ring = polyg->Exterior;
933 	    }
934 	  else
935 	      ring = gaiaAddInteriorRing (polyg, ib - 1, nverts);
936 	  for (iv = 0; iv < nverts; iv++)
937 	    {
938 		if (iv == 0 || iv == (nverts - 1))
939 		  {
940 		      /* first and last vertices are uncompressed */
941 		      x = gaiaImport64 (geo->blob + geo->offset, geo->endian,
942 					geo->endian_arch);
943 		      y = gaiaImport64 (geo->blob + (geo->offset + 8),
944 					geo->endian, geo->endian_arch);
945 		      z = gaiaImport64 (geo->blob + (geo->offset + 16),
946 					geo->endian, geo->endian_arch);
947 		      m = gaiaImport64 (geo->blob + (geo->offset + 24),
948 					geo->endian, geo->endian_arch);
949 		      geo->offset += 32;
950 		  }
951 		else
952 		  {
953 		      /* any other intermediate vertex is compressed */
954 		      fx = gaiaImportF32 (geo->blob + geo->offset, geo->endian,
955 					  geo->endian_arch);
956 		      fy = gaiaImportF32 (geo->blob + (geo->offset + 4),
957 					  geo->endian, geo->endian_arch);
958 		      fz = gaiaImportF32 (geo->blob + (geo->offset + 8),
959 					  geo->endian, geo->endian_arch);
960 		      m = gaiaImport64 (geo->blob + (geo->offset + 12),
961 					geo->endian, geo->endian_arch);
962 		      x = last_x + fx;
963 		      y = last_y + fy;
964 		      z = last_z + fz;
965 		      geo->offset += 20;
966 		  }
967 		gaiaSetPointXYZM (ring->Coords, iv, x, y, z, m);
968 		last_x = x;
969 		last_y = y;
970 		last_z = z;
971 	    }
972       }
973 }
974 
975 static void
ParseWkbGeometry(gaiaGeomCollPtr geo,int isWKB)976 ParseWkbGeometry (gaiaGeomCollPtr geo, int isWKB)
977 {
978 /* decodes a MULTIxx or GEOMETRYCOLLECTION from SpatiaLite BLOB */
979     int entities;
980     int type;
981     int ie;
982     if (geo->size < geo->offset + 4)
983 	return;
984     entities =
985 	gaiaImport32 (geo->blob + geo->offset, geo->endian, geo->endian_arch);
986     geo->offset += 4;
987     for (ie = 0; ie < entities; ie++)
988       {
989 	  if (geo->size < geo->offset + 5)
990 	      return;
991 	  if (isWKB)
992 	    {
993 		/* vanilla WKB could be encoded as mixed big-/little-endian sub-items */
994 		if (*(geo->blob + geo->offset) == 0x01)
995 		    geo->endian = GAIA_LITTLE_ENDIAN;
996 		else
997 		    geo->endian = GAIA_BIG_ENDIAN;
998 	    }
999 	  type =
1000 	      gaiaImport32 (geo->blob + geo->offset + 1, geo->endian,
1001 			    geo->endian_arch);
1002 	  geo->offset += 5;
1003 	  switch (type)
1004 	    {
1005 	    case GAIA_POINT:
1006 		ParseWkbPoint (geo);
1007 		break;
1008 	    case GAIA_POINTZ:
1009 	    case GAIA_GEOSWKB_POINTZ:
1010 		ParseWkbPointZ (geo);
1011 		break;
1012 	    case GAIA_POINTM:
1013 		ParseWkbPointM (geo);
1014 		break;
1015 	    case GAIA_POINTZM:
1016 		ParseWkbPointZM (geo);
1017 		break;
1018 	    case GAIA_LINESTRING:
1019 		ParseWkbLine (geo);
1020 		break;
1021 	    case GAIA_LINESTRINGZ:
1022 	    case GAIA_GEOSWKB_LINESTRINGZ:
1023 		ParseWkbLineZ (geo);
1024 		break;
1025 	    case GAIA_LINESTRINGM:
1026 		ParseWkbLineM (geo);
1027 		break;
1028 	    case GAIA_LINESTRINGZM:
1029 		ParseWkbLineZM (geo);
1030 		break;
1031 	    case GAIA_POLYGON:
1032 		ParseWkbPolygon (geo);
1033 		break;
1034 	    case GAIA_POLYGONZ:
1035 	    case GAIA_GEOSWKB_POLYGONZ:
1036 		ParseWkbPolygonZ (geo);
1037 		break;
1038 	    case GAIA_POLYGONM:
1039 		ParseWkbPolygonM (geo);
1040 		break;
1041 	    case GAIA_POLYGONZM:
1042 		ParseWkbPolygonZM (geo);
1043 		break;
1044 	    case GAIA_COMPRESSED_LINESTRING:
1045 		ParseCompressedWkbLine (geo);
1046 		break;
1047 	    case GAIA_COMPRESSED_LINESTRINGZ:
1048 		ParseCompressedWkbLineZ (geo);
1049 		break;
1050 	    case GAIA_COMPRESSED_LINESTRINGM:
1051 		ParseCompressedWkbLineM (geo);
1052 		break;
1053 	    case GAIA_COMPRESSED_LINESTRINGZM:
1054 		ParseCompressedWkbLineZM (geo);
1055 		break;
1056 	    case GAIA_COMPRESSED_POLYGON:
1057 		ParseCompressedWkbPolygon (geo);
1058 		break;
1059 	    case GAIA_COMPRESSED_POLYGONZ:
1060 		ParseCompressedWkbPolygonZ (geo);
1061 		break;
1062 	    case GAIA_COMPRESSED_POLYGONM:
1063 		ParseCompressedWkbPolygonM (geo);
1064 		break;
1065 	    case GAIA_COMPRESSED_POLYGONZM:
1066 		ParseCompressedWkbPolygonZM (geo);
1067 		break;
1068 	    default:
1069 		break;
1070 	    };
1071       }
1072 }
1073 
1074 static gaiaGeomCollPtr
doParseTinyPointBlob(const unsigned char * blob,unsigned int size)1075 doParseTinyPointBlob (const unsigned char *blob, unsigned int size)
1076 {
1077 /* decoding from SpatiaLite TinyPoint BLOB to GEOMETRY */
1078     unsigned char pointType;
1079     int type;
1080     int little_endian;
1081     int endian_arch = gaiaEndianArch ();
1082     gaiaGeomCollPtr geo = NULL;
1083 
1084     if (size < 24)
1085 	return NULL;		/* cannot be an internal BLOB TinyPoint geometry */
1086     if (*(blob + 0) != GAIA_MARK_START)
1087 	return NULL;		/* failed to recognize START signature */
1088     if (*(blob + (size - 1)) != GAIA_MARK_END)
1089 	return NULL;		/* failed to recognize END signature */
1090     if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN)
1091 	little_endian = 1;
1092     else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
1093 	little_endian = 0;
1094     else
1095 	return NULL;		/* unknown encoding; nor little-endian neither big-endian */
1096 
1097     pointType = *(blob + 6);
1098     geo = gaiaAllocGeomColl ();
1099     geo->Srid = gaiaImport32 (blob + 2, little_endian, endian_arch);
1100     geo->endian_arch = (char) endian_arch;
1101     geo->endian = (char) little_endian;
1102     geo->blob = blob;
1103     geo->size = size;
1104     geo->offset = 7;
1105     switch (pointType)
1106       {
1107 	  /* setting up DimensionModel */
1108       case GAIA_TINYPOINT_XYZ:
1109 	  type = GAIA_POINTZ;
1110 	  geo->DimensionModel = GAIA_XY_Z;
1111 	  break;
1112       case GAIA_TINYPOINT_XYM:
1113 	  type = GAIA_POINTM;
1114 	  geo->DimensionModel = GAIA_XY_M;
1115 	  break;
1116       case GAIA_TINYPOINT_XYZM:
1117 	  type = GAIA_POINTZM;
1118 	  geo->DimensionModel = GAIA_XY_Z_M;
1119 	  break;
1120       default:
1121 	  type = GAIA_POINT;
1122 	  geo->DimensionModel = GAIA_XY;
1123 	  break;
1124       };
1125     switch (type)
1126       {
1127 	  /* parsing elementary geometries */
1128       case GAIA_POINT:
1129 	  ParseWkbPoint (geo);
1130 	  break;
1131       case GAIA_POINTZ:
1132 	  ParseWkbPointZ (geo);
1133 	  break;
1134       case GAIA_POINTM:
1135 	  ParseWkbPointM (geo);
1136 	  break;
1137       case GAIA_POINTZM:
1138 	  ParseWkbPointZM (geo);
1139 	  break;
1140       default:
1141 	  break;
1142       };
1143     geo->MinX = geo->FirstPoint->X;
1144     geo->MinY = geo->FirstPoint->Y;
1145     geo->MaxX = geo->FirstPoint->X;
1146     geo->MaxY = geo->FirstPoint->Y;
1147     geo->DeclaredType = GAIA_POINT;
1148     return geo;
1149 }
1150 
1151 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromSpatiaLiteBlobWkbEx(const unsigned char * blob,unsigned int size,int gpkg_mode,int gpkg_amphibious)1152 gaiaFromSpatiaLiteBlobWkbEx (const unsigned char *blob, unsigned int size,
1153 			     int gpkg_mode, int gpkg_amphibious)
1154 {
1155 /* decoding from SpatiaLite BLOB to GEOMETRY */
1156     int type;
1157     int little_endian;
1158     int endian_arch = gaiaEndianArch ();
1159     gaiaGeomCollPtr geo = NULL;
1160 
1161     if (gpkg_amphibious || gpkg_mode)
1162       {
1163 #ifdef ENABLE_GEOPACKAGE	/* GEOPACKAGE enabled: supporting GPKG geometries */
1164 	  if (gaiaIsValidGPB (blob, size))
1165 	    {
1166 		geo = gaiaFromGeoPackageGeometryBlob (blob, size);
1167 		if (geo != NULL)
1168 		    return geo;
1169 	    }
1170 	  if (gpkg_mode)
1171 	      return NULL;	/* must accept only GPKG geometries */
1172 #else
1173 	  ;
1174 #endif /* end GEOPACKAGE: supporting GPKG geometries */
1175       }
1176 
1177     if (size == 24 || size == 32 || size == 40)
1178       {
1179 	  /* testing for a possible TinyPoint BLOB */
1180 	  if (*(blob + 0) == GAIA_MARK_START &&
1181 	      (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN
1182 	       || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
1183 	      && *(blob + (size - 1)) == GAIA_MARK_END)
1184 	      return doParseTinyPointBlob (blob, size);
1185       }
1186 
1187     if (size < 45)
1188 	return NULL;		/* cannot be an internal BLOB WKB geometry */
1189     if (*(blob + 0) != GAIA_MARK_START)
1190 	return NULL;		/* failed to recognize START signature */
1191     if (*(blob + (size - 1)) != GAIA_MARK_END)
1192 	return NULL;		/* failed to recognize END signature */
1193     if (*(blob + 38) != GAIA_MARK_MBR)
1194 	return NULL;		/* failed to recognize MBR signature */
1195     if (*(blob + 1) == GAIA_LITTLE_ENDIAN)
1196 	little_endian = 1;
1197     else if (*(blob + 1) == GAIA_BIG_ENDIAN)
1198 	little_endian = 0;
1199     else
1200 	return NULL;		/* unknown encoding; nor little-endian neither big-endian */
1201     type = gaiaImport32 (blob + 39, little_endian, endian_arch);
1202     geo = gaiaAllocGeomColl ();
1203     geo->Srid = gaiaImport32 (blob + 2, little_endian, endian_arch);
1204     geo->endian_arch = (char) endian_arch;
1205     geo->endian = (char) little_endian;
1206     geo->blob = blob;
1207     geo->size = size;
1208     geo->offset = 43;
1209     switch (type)
1210       {
1211 	  /* setting up DimensionModel */
1212       case GAIA_POINTZ:
1213       case GAIA_LINESTRINGZ:
1214       case GAIA_POLYGONZ:
1215       case GAIA_MULTIPOINTZ:
1216       case GAIA_MULTILINESTRINGZ:
1217       case GAIA_MULTIPOLYGONZ:
1218       case GAIA_GEOMETRYCOLLECTIONZ:
1219       case GAIA_COMPRESSED_LINESTRINGZ:
1220       case GAIA_COMPRESSED_POLYGONZ:
1221 	  geo->DimensionModel = GAIA_XY_Z;
1222 	  break;
1223       case GAIA_POINTM:
1224       case GAIA_LINESTRINGM:
1225       case GAIA_POLYGONM:
1226       case GAIA_MULTIPOINTM:
1227       case GAIA_MULTILINESTRINGM:
1228       case GAIA_MULTIPOLYGONM:
1229       case GAIA_GEOMETRYCOLLECTIONM:
1230       case GAIA_COMPRESSED_LINESTRINGM:
1231       case GAIA_COMPRESSED_POLYGONM:
1232 	  geo->DimensionModel = GAIA_XY_M;
1233 	  break;
1234       case GAIA_POINTZM:
1235       case GAIA_LINESTRINGZM:
1236       case GAIA_POLYGONZM:
1237       case GAIA_MULTIPOINTZM:
1238       case GAIA_MULTILINESTRINGZM:
1239       case GAIA_MULTIPOLYGONZM:
1240       case GAIA_GEOMETRYCOLLECTIONZM:
1241       case GAIA_COMPRESSED_LINESTRINGZM:
1242       case GAIA_COMPRESSED_POLYGONZM:
1243 	  geo->DimensionModel = GAIA_XY_Z_M;
1244 	  break;
1245       default:
1246 	  geo->DimensionModel = GAIA_XY;
1247 	  break;
1248       };
1249     switch (type)
1250       {
1251 	  /* parsing elementary geometries */
1252       case GAIA_POINT:
1253 	  ParseWkbPoint (geo);
1254 	  break;
1255       case GAIA_POINTZ:
1256 	  ParseWkbPointZ (geo);
1257 	  break;
1258       case GAIA_POINTM:
1259 	  ParseWkbPointM (geo);
1260 	  break;
1261       case GAIA_POINTZM:
1262 	  ParseWkbPointZM (geo);
1263 	  break;
1264       case GAIA_LINESTRING:
1265 	  ParseWkbLine (geo);
1266 	  break;
1267       case GAIA_LINESTRINGZ:
1268 	  ParseWkbLineZ (geo);
1269 	  break;
1270       case GAIA_LINESTRINGM:
1271 	  ParseWkbLineM (geo);
1272 	  break;
1273       case GAIA_LINESTRINGZM:
1274 	  ParseWkbLineZM (geo);
1275 	  break;
1276       case GAIA_POLYGON:
1277 	  ParseWkbPolygon (geo);
1278 	  break;
1279       case GAIA_POLYGONZ:
1280 	  ParseWkbPolygonZ (geo);
1281 	  break;
1282       case GAIA_POLYGONM:
1283 	  ParseWkbPolygonM (geo);
1284 	  break;
1285       case GAIA_POLYGONZM:
1286 	  ParseWkbPolygonZM (geo);
1287 	  break;
1288       case GAIA_COMPRESSED_LINESTRING:
1289 	  ParseCompressedWkbLine (geo);
1290 	  break;
1291       case GAIA_COMPRESSED_LINESTRINGZ:
1292 	  ParseCompressedWkbLineZ (geo);
1293 	  break;
1294       case GAIA_COMPRESSED_LINESTRINGM:
1295 	  ParseCompressedWkbLineM (geo);
1296 	  break;
1297       case GAIA_COMPRESSED_LINESTRINGZM:
1298 	  ParseCompressedWkbLineZM (geo);
1299 	  break;
1300       case GAIA_COMPRESSED_POLYGON:
1301 	  ParseCompressedWkbPolygon (geo);
1302 	  break;
1303       case GAIA_COMPRESSED_POLYGONZ:
1304 	  ParseCompressedWkbPolygonZ (geo);
1305 	  break;
1306       case GAIA_COMPRESSED_POLYGONM:
1307 	  ParseCompressedWkbPolygonM (geo);
1308 	  break;
1309       case GAIA_COMPRESSED_POLYGONZM:
1310 	  ParseCompressedWkbPolygonZM (geo);
1311 	  break;
1312       case GAIA_MULTIPOINT:
1313       case GAIA_MULTIPOINTZ:
1314       case GAIA_MULTIPOINTM:
1315       case GAIA_MULTIPOINTZM:
1316       case GAIA_MULTILINESTRING:
1317       case GAIA_MULTILINESTRINGZ:
1318       case GAIA_MULTILINESTRINGM:
1319       case GAIA_MULTILINESTRINGZM:
1320       case GAIA_MULTIPOLYGON:
1321       case GAIA_MULTIPOLYGONZ:
1322       case GAIA_MULTIPOLYGONM:
1323       case GAIA_MULTIPOLYGONZM:
1324       case GAIA_GEOMETRYCOLLECTION:
1325       case GAIA_GEOMETRYCOLLECTIONZ:
1326       case GAIA_GEOMETRYCOLLECTIONM:
1327       case GAIA_GEOMETRYCOLLECTIONZM:
1328 	  ParseWkbGeometry (geo, 0);
1329 	  break;
1330       default:
1331 	  break;
1332       };
1333     geo->MinX = gaiaImport64 (blob + 6, little_endian, endian_arch);
1334     geo->MinY = gaiaImport64 (blob + 14, little_endian, endian_arch);
1335     geo->MaxX = gaiaImport64 (blob + 22, little_endian, endian_arch);
1336     geo->MaxY = gaiaImport64 (blob + 30, little_endian, endian_arch);
1337     switch (type)
1338       {
1339 	  /* setting up DeclaredType */
1340       case GAIA_POINT:
1341       case GAIA_POINTZ:
1342       case GAIA_POINTM:
1343       case GAIA_POINTZM:
1344 	  geo->DeclaredType = GAIA_POINT;
1345 	  break;
1346       case GAIA_LINESTRING:
1347       case GAIA_LINESTRINGZ:
1348       case GAIA_LINESTRINGM:
1349       case GAIA_LINESTRINGZM:
1350       case GAIA_COMPRESSED_LINESTRING:
1351       case GAIA_COMPRESSED_LINESTRINGZ:
1352       case GAIA_COMPRESSED_LINESTRINGM:
1353       case GAIA_COMPRESSED_LINESTRINGZM:
1354 	  geo->DeclaredType = GAIA_LINESTRING;
1355 	  break;
1356       case GAIA_POLYGON:
1357       case GAIA_POLYGONZ:
1358       case GAIA_POLYGONM:
1359       case GAIA_POLYGONZM:
1360       case GAIA_COMPRESSED_POLYGON:
1361       case GAIA_COMPRESSED_POLYGONZ:
1362       case GAIA_COMPRESSED_POLYGONM:
1363       case GAIA_COMPRESSED_POLYGONZM:
1364 	  geo->DeclaredType = GAIA_POLYGON;
1365 	  break;
1366       case GAIA_MULTIPOINT:
1367       case GAIA_MULTIPOINTZ:
1368       case GAIA_MULTIPOINTM:
1369       case GAIA_MULTIPOINTZM:
1370 	  geo->DeclaredType = GAIA_MULTIPOINT;
1371 	  break;
1372       case GAIA_MULTILINESTRING:
1373       case GAIA_MULTILINESTRINGZ:
1374       case GAIA_MULTILINESTRINGM:
1375       case GAIA_MULTILINESTRINGZM:
1376 	  geo->DeclaredType = GAIA_MULTILINESTRING;
1377 	  break;
1378       case GAIA_MULTIPOLYGON:
1379       case GAIA_MULTIPOLYGONZ:
1380       case GAIA_MULTIPOLYGONM:
1381       case GAIA_MULTIPOLYGONZM:
1382 	  geo->DeclaredType = GAIA_MULTIPOLYGON;
1383 	  break;
1384       case GAIA_GEOMETRYCOLLECTION:
1385       case GAIA_GEOMETRYCOLLECTIONZ:
1386       case GAIA_GEOMETRYCOLLECTIONM:
1387       case GAIA_GEOMETRYCOLLECTIONZM:
1388 	  geo->DeclaredType = GAIA_GEOMETRYCOLLECTION;
1389 	  break;
1390       default:
1391 	  geo->DeclaredType = GAIA_UNKNOWN;
1392 	  break;
1393       };
1394     return geo;
1395 }
1396 
1397 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromSpatiaLiteBlobWkb(const unsigned char * blob,unsigned int size)1398 gaiaFromSpatiaLiteBlobWkb (const unsigned char *blob, unsigned int size)
1399 {
1400 /*
1401 * decoding from SpatiaLite BLOB to GEOMETRY
1402 * convenience method - always disabling GPKG compatibility Modes
1403 */
1404     return gaiaFromSpatiaLiteBlobWkbEx (blob, size, 0, 0);
1405 }
1406 
1407 static gaiaGeomCollPtr
doParseTinyPointBlobMbr(const unsigned char * blob,unsigned int size)1408 doParseTinyPointBlobMbr (const unsigned char *blob, unsigned int size)
1409 {
1410 /* decoding from SpatiaLite TinyPoint BLOB (MBR only) */
1411     int little_endian;
1412     int endian_arch = gaiaEndianArch ();
1413     double x;
1414     double y;
1415     gaiaGeomCollPtr geo = NULL;
1416     gaiaPolygonPtr polyg;
1417     gaiaRingPtr ring;
1418 
1419     if (size < 24)
1420 	return NULL;		/* cannot be an internal BLOB TinyPoint geometry */
1421     if (*(blob + 0) != GAIA_MARK_START)
1422 	return NULL;		/* failed to recognize START signature */
1423     if (*(blob + (size - 1)) != GAIA_MARK_END)
1424 	return NULL;		/* failed to recognize END signature */
1425     if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN)
1426 	little_endian = 1;
1427     else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
1428 	little_endian = 0;
1429     else
1430 	return NULL;		/* unknown encoding; nor little-endian neither big-endian */
1431 
1432     x = gaiaImport64 (blob + 7, little_endian, endian_arch);
1433     y = gaiaImport64 (blob + 15, little_endian, endian_arch);
1434 
1435     geo = gaiaAllocGeomColl ();
1436     polyg = gaiaAddPolygonToGeomColl (geo, 5, 0);
1437     ring = polyg->Exterior;
1438     gaiaSetPoint (ring->Coords, 0, x, y);	/* vertex # 1 */
1439     gaiaSetPoint (ring->Coords, 1, x, y);	/* vertex # 2 */
1440     gaiaSetPoint (ring->Coords, 2, x, y);	/* vertex # 3 */
1441     gaiaSetPoint (ring->Coords, 3, x, y);	/* vertex # 4 */
1442     gaiaSetPoint (ring->Coords, 4, x, y);	/* vertex # 5 [same as vertex # 1 to close the polygon] */
1443     return geo;
1444 }
1445 
1446 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromSpatiaLiteBlobMbr(const unsigned char * blob,unsigned int size)1447 gaiaFromSpatiaLiteBlobMbr (const unsigned char *blob, unsigned int size)
1448 {
1449 /* decoding from SpatiaLite BLOB to GEOMETRY [MBR only] */
1450     int little_endian;
1451     int endian_arch = gaiaEndianArch ();
1452     double minx;
1453     double miny;
1454     double maxx;
1455     double maxy;
1456     gaiaGeomCollPtr geo = NULL;
1457     gaiaPolygonPtr polyg;
1458     gaiaRingPtr ring;
1459 
1460     if (size == 24 || size == 32 || size == 40)
1461       {
1462 	  /* testing for a possible TinyPoint BLOB */
1463 	  if (*(blob + 0) == GAIA_MARK_START &&
1464 	      (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN
1465 	       || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
1466 	      && *(blob + (size - 1)) == GAIA_MARK_END)
1467 	      return doParseTinyPointBlobMbr (blob, size);
1468       }
1469     if (size < 45)
1470 	return NULL;		/* cannot be an internal BLOB WKB geometry */
1471     if (*(blob + 0) != GAIA_MARK_START)
1472 	return NULL;		/* failed to recognize START signature */
1473     if (*(blob + (size - 1)) != GAIA_MARK_END)
1474 	return NULL;		/* failed to recognize END signature */
1475     if (*(blob + 38) != GAIA_MARK_MBR)
1476 	return NULL;		/* failed to recognize MBR signature */
1477     if (*(blob + 1) == GAIA_LITTLE_ENDIAN)
1478 	little_endian = 1;
1479     else if (*(blob + 1) == GAIA_BIG_ENDIAN)
1480 	little_endian = 0;
1481     else
1482 	return NULL;		/* unknown encoding; nor litte-endian neither big-endian */
1483     geo = gaiaAllocGeomColl ();
1484     polyg = gaiaAddPolygonToGeomColl (geo, 5, 0);
1485     ring = polyg->Exterior;
1486     minx = gaiaImport64 (blob + 6, little_endian, endian_arch);
1487     miny = gaiaImport64 (blob + 14, little_endian, endian_arch);
1488     maxx = gaiaImport64 (blob + 22, little_endian, endian_arch);
1489     maxy = gaiaImport64 (blob + 30, little_endian, endian_arch);
1490     gaiaSetPoint (ring->Coords, 0, minx, miny);	/* vertex # 1 */
1491     gaiaSetPoint (ring->Coords, 1, maxx, miny);	/* vertex # 2 */
1492     gaiaSetPoint (ring->Coords, 2, maxx, maxy);	/* vertex # 3 */
1493     gaiaSetPoint (ring->Coords, 3, minx, maxy);	/* vertex # 4 */
1494     gaiaSetPoint (ring->Coords, 4, minx, miny);	/* vertex # 5 [same as vertex # 1 to close the polygon] */
1495     return geo;
1496 }
1497 
1498 GAIAGEO_DECLARE void
gaiaToSpatiaLiteBlobWkbEx(gaiaGeomCollPtr geom,unsigned char ** result,int * size,int gpkg_mode)1499 gaiaToSpatiaLiteBlobWkbEx (gaiaGeomCollPtr geom, unsigned char **result,
1500 			   int *size, int gpkg_mode)
1501 {
1502 /* simply defaults to gaiaToSpatiaLiteBlobWkbEx2 tiny_point=FALSE */
1503     gaiaToSpatiaLiteBlobWkbEx2 (geom, result, size, gpkg_mode, 0);
1504 }
1505 
1506 static void
doEncodeTinyPointBlob(gaiaGeomCollPtr geom,unsigned char ** result,int * size)1507 doEncodeTinyPointBlob (gaiaGeomCollPtr geom, unsigned char **result, int *size)
1508 {
1509 /* encoding a TinyPoint BLOB */
1510     int sz;
1511     unsigned char *blob;
1512     unsigned char *ptr;
1513     int endian_arch = gaiaEndianArch ();
1514     gaiaPointPtr point = geom->FirstPoint;
1515 
1516 /* compunting the BLOB size */
1517     if (geom->DimensionModel == GAIA_XY_Z)
1518 	sz = 32;
1519     else if (geom->DimensionModel == GAIA_XY_M)
1520 	sz = 32;
1521     else if (geom->DimensionModel == GAIA_XY_Z_M)
1522 	sz = 40;
1523     else
1524 	sz = 24;
1525 /* allocating the BLOB */
1526     blob = malloc (sz);
1527     ptr = blob;
1528 /* and finally we build the BLOB */
1529     *ptr = GAIA_MARK_START;	/* START signature */
1530     ptr++;
1531     *(ptr) = GAIA_TINYPOINT_LITTLE_ENDIAN;	/* byte ordering */
1532     ptr++;
1533     gaiaExport32 (ptr, geom->Srid, 1, endian_arch);	/* the SRID */
1534     ptr += 4;
1535     if (geom->DimensionModel == GAIA_XY_Z)
1536 	*ptr = GAIA_TINYPOINT_XYZ;
1537     else if (geom->DimensionModel == GAIA_XY_M)
1538 	*ptr = GAIA_TINYPOINT_XYM;
1539     else if (geom->DimensionModel == GAIA_XY_Z_M)
1540 	*ptr = GAIA_TINYPOINT_XYZM;
1541     else
1542 	*ptr = GAIA_TINYPOINT_XY;
1543     ptr++;
1544     gaiaExport64 (ptr, point->X, 1, endian_arch);	/* X */
1545     ptr += 8;
1546     gaiaExport64 (ptr, point->Y, 1, endian_arch);	/* Y */
1547     ptr += 8;
1548     if (geom->DimensionModel == GAIA_XY_Z)
1549       {
1550 	  gaiaExport64 (ptr, point->Z, 1, endian_arch);	/* Z */
1551 	  ptr += 8;
1552       }
1553     else if (geom->DimensionModel == GAIA_XY_M)
1554       {
1555 	  gaiaExport64 (ptr, point->M, 1, endian_arch);	/* M */
1556 	  ptr += 8;
1557       }
1558     else if (geom->DimensionModel == GAIA_XY_Z_M)
1559       {
1560 	  gaiaExport64 (ptr, point->Z, 1, endian_arch);	/* Z */
1561 	  ptr += 8;
1562 	  gaiaExport64 (ptr, point->M, 1, endian_arch);	/* M */
1563 	  ptr += 8;
1564       }
1565     *ptr = GAIA_MARK_END;	/* END signature */
1566 
1567     *result = blob;
1568     *size = sz;
1569 }
1570 
1571 GAIAGEO_DECLARE void
gaiaToSpatiaLiteBlobWkbEx2(gaiaGeomCollPtr geom,unsigned char ** result,int * size,int gpkg_mode,int tiny_point)1572 gaiaToSpatiaLiteBlobWkbEx2 (gaiaGeomCollPtr geom, unsigned char **result,
1573 			    int *size, int gpkg_mode, int tiny_point)
1574 {
1575 /* builds the SpatiaLite BLOB representation for this GEOMETRY */
1576     int ib;
1577     int iv;
1578     double x;
1579     double y;
1580     double z = 0.0;
1581     double m = 0.0;
1582     int entities = 0;
1583     int n_points = 0;
1584     int n_linestrings = 0;
1585     int n_polygons = 0;
1586     int type;
1587     unsigned char *ptr;
1588     gaiaPointPtr pt;
1589     gaiaLinestringPtr ln;
1590     gaiaPolygonPtr pg;
1591     gaiaRingPtr rng;
1592     gaiaPointPtr point = NULL;
1593     gaiaLinestringPtr line = NULL;
1594     gaiaPolygonPtr polyg = NULL;
1595     int endian_arch = gaiaEndianArch ();
1596     gaiaMbrGeometry (geom);
1597 
1598     if (gpkg_mode)
1599       {
1600 #ifdef ENABLE_GEOPACKAGE	/* only if GeoPackage support is enabled */
1601 	  /* GeoPackage Mode enabled */
1602 	  gaiaToGPB (geom, result, size);
1603 #endif /* end GEOPACKAGE conditional */
1604 	  return;
1605       }
1606 
1607 /* how many entities, and of what kind, do we have ? */
1608     pt = geom->FirstPoint;
1609     while (pt)
1610       {
1611 	  point = pt;
1612 	  entities++;
1613 	  n_points++;
1614 	  pt = pt->Next;
1615       }
1616     ln = geom->FirstLinestring;
1617     while (ln)
1618       {
1619 	  line = ln;
1620 	  entities++;
1621 	  n_linestrings++;
1622 	  ln = ln->Next;
1623       }
1624     pg = geom->FirstPolygon;
1625     while (pg)
1626       {
1627 	  polyg = pg;
1628 	  entities++;
1629 	  n_polygons++;
1630 	  pg = pg->Next;
1631       }
1632 
1633     *size = 0;
1634     *result = NULL;
1635     if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
1636 	return;
1637     if (n_points == 1 && n_linestrings == 0 && n_polygons == 0 && entities == 1
1638 	&& geom->DeclaredType != GAIA_MULTIPOINT
1639 	&& geom->DeclaredType != GAIA_GEOMETRYCOLLECTION && tiny_point)
1640       {
1641 	  /* using the TinyPoint BLOB encoding */
1642 	  doEncodeTinyPointBlob (geom, result, size);
1643 	  return;
1644       }
1645 
1646 /* ok, we can determine the geometry class */
1647     if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
1648       {
1649 	  if (geom->DeclaredType == GAIA_MULTIPOINT)
1650 	    {
1651 		if (geom->DimensionModel == GAIA_XY_Z)
1652 		    type = GAIA_MULTIPOINTZ;
1653 		else if (geom->DimensionModel == GAIA_XY_M)
1654 		    type = GAIA_MULTIPOINTM;
1655 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1656 		    type = GAIA_MULTIPOINTZM;
1657 		else
1658 		    type = GAIA_MULTIPOINT;
1659 	    }
1660 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1661 	    {
1662 		if (geom->DimensionModel == GAIA_XY_Z)
1663 		    type = GAIA_GEOMETRYCOLLECTIONZ;
1664 		else if (geom->DimensionModel == GAIA_XY_M)
1665 		    type = GAIA_GEOMETRYCOLLECTIONM;
1666 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1667 		    type = GAIA_GEOMETRYCOLLECTIONZM;
1668 		else
1669 		    type = GAIA_GEOMETRYCOLLECTION;
1670 	    }
1671 	  else
1672 	    {
1673 		if (geom->DimensionModel == GAIA_XY_Z)
1674 		    type = GAIA_POINTZ;
1675 		else if (geom->DimensionModel == GAIA_XY_M)
1676 		    type = GAIA_POINTM;
1677 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1678 		    type = GAIA_POINTZM;
1679 		else
1680 		    type = GAIA_POINT;
1681 	    }
1682       }
1683     else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
1684       {
1685 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1686 	    {
1687 		if (geom->DimensionModel == GAIA_XY_Z)
1688 		    type = GAIA_GEOMETRYCOLLECTIONZ;
1689 		else if (geom->DimensionModel == GAIA_XY_M)
1690 		    type = GAIA_GEOMETRYCOLLECTIONM;
1691 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1692 		    type = GAIA_GEOMETRYCOLLECTIONZM;
1693 		else
1694 		    type = GAIA_GEOMETRYCOLLECTION;
1695 	    }
1696 	  else
1697 	    {
1698 		if (geom->DimensionModel == GAIA_XY_Z)
1699 		    type = GAIA_MULTIPOINTZ;
1700 		else if (geom->DimensionModel == GAIA_XY_M)
1701 		    type = GAIA_MULTIPOINTM;
1702 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1703 		    type = GAIA_MULTIPOINTZM;
1704 		else
1705 		    type = GAIA_MULTIPOINT;
1706 	    }
1707       }
1708     else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
1709       {
1710 	  if (geom->DeclaredType == GAIA_MULTILINESTRING)
1711 	    {
1712 		if (geom->DimensionModel == GAIA_XY_Z)
1713 		    type = GAIA_MULTILINESTRINGZ;
1714 		else if (geom->DimensionModel == GAIA_XY_M)
1715 		    type = GAIA_MULTILINESTRINGM;
1716 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1717 		    type = GAIA_MULTILINESTRINGZM;
1718 		else
1719 		    type = GAIA_MULTILINESTRING;
1720 	    }
1721 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1722 	    {
1723 		if (geom->DimensionModel == GAIA_XY_Z)
1724 		    type = GAIA_GEOMETRYCOLLECTIONZ;
1725 		else if (geom->DimensionModel == GAIA_XY_M)
1726 		    type = GAIA_GEOMETRYCOLLECTIONM;
1727 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1728 		    type = GAIA_GEOMETRYCOLLECTIONZM;
1729 		else
1730 		    type = GAIA_GEOMETRYCOLLECTION;
1731 	    }
1732 	  else
1733 	    {
1734 		if (geom->DimensionModel == GAIA_XY_Z)
1735 		    type = GAIA_LINESTRINGZ;
1736 		else if (geom->DimensionModel == GAIA_XY_M)
1737 		    type = GAIA_LINESTRINGM;
1738 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1739 		    type = GAIA_LINESTRINGZM;
1740 		else
1741 		    type = GAIA_LINESTRING;
1742 	    }
1743       }
1744     else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
1745       {
1746 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1747 	    {
1748 		if (geom->DimensionModel == GAIA_XY_Z)
1749 		    type = GAIA_GEOMETRYCOLLECTIONZ;
1750 		else if (geom->DimensionModel == GAIA_XY_M)
1751 		    type = GAIA_GEOMETRYCOLLECTIONM;
1752 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1753 		    type = GAIA_GEOMETRYCOLLECTIONZM;
1754 		else
1755 		    type = GAIA_GEOMETRYCOLLECTION;
1756 	    }
1757 	  else
1758 	    {
1759 		if (geom->DimensionModel == GAIA_XY_Z)
1760 		    type = GAIA_MULTILINESTRINGZ;
1761 		else if (geom->DimensionModel == GAIA_XY_M)
1762 		    type = GAIA_MULTILINESTRINGM;
1763 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1764 		    type = GAIA_MULTILINESTRINGZM;
1765 		else
1766 		    type = GAIA_MULTILINESTRING;
1767 	    }
1768       }
1769     else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
1770       {
1771 	  if (geom->DeclaredType == GAIA_MULTIPOLYGON)
1772 	    {
1773 		if (geom->DimensionModel == GAIA_XY_Z)
1774 		    type = GAIA_MULTIPOLYGONZ;
1775 		else if (geom->DimensionModel == GAIA_XY_M)
1776 		    type = GAIA_MULTIPOLYGONM;
1777 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1778 		    type = GAIA_MULTIPOLYGONZM;
1779 		else
1780 		    type = GAIA_MULTIPOLYGON;
1781 	    }
1782 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1783 	    {
1784 		if (geom->DimensionModel == GAIA_XY_Z)
1785 		    type = GAIA_GEOMETRYCOLLECTIONZ;
1786 		else if (geom->DimensionModel == GAIA_XY_M)
1787 		    type = GAIA_GEOMETRYCOLLECTIONM;
1788 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1789 		    type = GAIA_GEOMETRYCOLLECTIONZM;
1790 		else
1791 		    type = GAIA_GEOMETRYCOLLECTION;
1792 	    }
1793 	  else
1794 	    {
1795 		if (geom->DimensionModel == GAIA_XY_Z)
1796 		    type = GAIA_POLYGONZ;
1797 		else if (geom->DimensionModel == GAIA_XY_M)
1798 		    type = GAIA_POLYGONM;
1799 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1800 		    type = GAIA_POLYGONZM;
1801 		else
1802 		    type = GAIA_POLYGON;
1803 	    }
1804       }
1805     else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
1806       {
1807 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
1808 	    {
1809 		if (geom->DimensionModel == GAIA_XY_Z)
1810 		    type = GAIA_GEOMETRYCOLLECTIONZ;
1811 		else if (geom->DimensionModel == GAIA_XY_M)
1812 		    type = GAIA_GEOMETRYCOLLECTIONM;
1813 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1814 		    type = GAIA_GEOMETRYCOLLECTIONZM;
1815 		else
1816 		    type = GAIA_GEOMETRYCOLLECTION;
1817 	    }
1818 	  else
1819 	    {
1820 		if (geom->DimensionModel == GAIA_XY_Z)
1821 		    type = GAIA_MULTIPOLYGONZ;
1822 		else if (geom->DimensionModel == GAIA_XY_M)
1823 		    type = GAIA_MULTIPOLYGONM;
1824 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1825 		    type = GAIA_MULTIPOLYGONZM;
1826 		else
1827 		    type = GAIA_MULTIPOLYGON;
1828 	    }
1829       }
1830     else
1831       {
1832 	  if (geom->DimensionModel == GAIA_XY_Z)
1833 	      type = GAIA_GEOMETRYCOLLECTIONZ;
1834 	  else if (geom->DimensionModel == GAIA_XY_M)
1835 	      type = GAIA_GEOMETRYCOLLECTIONM;
1836 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
1837 	      type = GAIA_GEOMETRYCOLLECTIONZM;
1838 	  else
1839 	      type = GAIA_GEOMETRYCOLLECTION;
1840       }
1841 /* and now we compute the size of BLOB */
1842     *size = 44;			/* header size */
1843     switch (type)
1844       {
1845       case GAIA_POINT:
1846 	  *size += (sizeof (double) * 2);	/* [x,y] coords */
1847 	  break;
1848       case GAIA_POINTZ:
1849 	  *size += (sizeof (double) * 3);	/* [x,y,z] coords */
1850 	  break;
1851       case GAIA_POINTM:
1852 	  *size += (sizeof (double) * 3);	/* [x,y,m] coords */
1853 	  break;
1854       case GAIA_POINTZM:
1855 	  *size += (sizeof (double) * 4);	/* [x,y,z,m] coords */
1856 	  break;
1857       case GAIA_LINESTRING:
1858 	  *size += (4 + ((sizeof (double) * 2) * line->Points));	/* # points + [x,y] for each vertex */
1859 	  break;
1860       case GAIA_LINESTRINGZ:
1861 	  *size += (4 + ((sizeof (double) * 3) * line->Points));	/* # points + [x,y,z] for each vertex */
1862 	  break;
1863       case GAIA_LINESTRINGM:
1864 	  *size += (4 + ((sizeof (double) * 3) * line->Points));	/* # points + [x,y,m] for each vertex */
1865 	  break;
1866       case GAIA_LINESTRINGZM:
1867 	  *size += (4 + ((sizeof (double) * 4) * line->Points));	/* # points + [x,y,z,m] for each vertex */
1868 	  break;
1869       case GAIA_POLYGON:
1870 	  rng = polyg->Exterior;
1871 	  *size += (8 + ((sizeof (double) * 2) * rng->Points));	/* # rings + # points + [x.y] array - exterior ring */
1872 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
1873 	    {
1874 		rng = polyg->Interiors + ib;
1875 		*size += (4 + ((sizeof (double) * 2) * rng->Points));	/* # points + [x,y] array - interior ring */
1876 	    }
1877 	  break;
1878       case GAIA_POLYGONZ:
1879 	  rng = polyg->Exterior;
1880 	  *size += (8 + ((sizeof (double) * 3) * rng->Points));	/* # rings + # points + [x,y,z] array - exterior ring */
1881 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
1882 	    {
1883 		rng = polyg->Interiors + ib;
1884 		*size += (4 + ((sizeof (double) * 3) * rng->Points));	/* # points + [x,y,z] array - interior ring */
1885 	    }
1886 	  break;
1887       case GAIA_POLYGONM:
1888 	  rng = polyg->Exterior;
1889 	  *size += (8 + ((sizeof (double) * 3) * rng->Points));	/* # rings + # points + [x,y,m] array - exterior ring */
1890 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
1891 	    {
1892 		rng = polyg->Interiors + ib;
1893 		*size += (4 + ((sizeof (double) * 3) * rng->Points));	/* # points + [x,y,m] array - interior ring */
1894 	    }
1895 	  break;
1896       case GAIA_POLYGONZM:
1897 	  rng = polyg->Exterior;
1898 	  *size += (8 + ((sizeof (double) * 4) * rng->Points));	/* # rings + # points + [x,y,z,m] array - exterior ring */
1899 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
1900 	    {
1901 		rng = polyg->Interiors + ib;
1902 		*size += (4 + ((sizeof (double) * 4) * rng->Points));	/* # points + [x,y,z,m] array - interior ring */
1903 	    }
1904 	  break;
1905       default:
1906 	  /* this one is not a simple geometry; should be a MULTIxxxx or a GEOMETRYCOLLECTION */
1907 	  *size += 4;		/* # entities */
1908 	  point = geom->FirstPoint;
1909 	  while (point)
1910 	    {
1911 		*size += 5;	/* entity header */
1912 		if (geom->DimensionModel == GAIA_XY_Z
1913 		    || geom->DimensionModel == GAIA_XY_M)
1914 		    *size += (sizeof (double) * 3);	/* three doubles for each POINT */
1915 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1916 		    *size += (sizeof (double) * 4);	/* four doubles for each POINT */
1917 		else
1918 		    *size += (sizeof (double) * 2);	/* two doubles for each POINT */
1919 		point = point->Next;
1920 	    }
1921 	  line = geom->FirstLinestring;
1922 	  while (line)
1923 	    {
1924 		*size += 5;	/* entity header */
1925 		if (geom->DimensionModel == GAIA_XY_Z
1926 		    || geom->DimensionModel == GAIA_XY_M)
1927 		    *size += (4 + ((sizeof (double) * 3) * line->Points));	/* # points + [x,y,z] for each vertex */
1928 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1929 		    *size += (4 + ((sizeof (double) * 4) * line->Points));	/* # points + [x,y,z,m] for each vertex */
1930 		else
1931 		    *size += (4 + ((sizeof (double) * 2) * line->Points));	/* # points + [x,y] for each vertex */
1932 		line = line->Next;
1933 	    }
1934 	  polyg = geom->FirstPolygon;
1935 	  while (polyg)
1936 	    {
1937 		*size += 5;	/* entity header */
1938 		rng = polyg->Exterior;
1939 		if (geom->DimensionModel == GAIA_XY_Z
1940 		    || geom->DimensionModel == GAIA_XY_M)
1941 		    *size += (8 + ((sizeof (double) * 3) * rng->Points));	/* # rings + # points + [x,y,z] array - exterior ring */
1942 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1943 		    *size += (8 + ((sizeof (double) * 4) * rng->Points));	/* # rings + # points + [x,y,z,m] array - exterior ring */
1944 		else
1945 		    *size += (8 + ((sizeof (double) * 2) * rng->Points));	/* # rings + # points + [x,y] array - exterior ring */
1946 		for (ib = 0; ib < polyg->NumInteriors; ib++)
1947 		  {
1948 		      rng = polyg->Interiors + ib;
1949 		      if (geom->DimensionModel == GAIA_XY_Z
1950 			  || geom->DimensionModel == GAIA_XY_M)
1951 			  *size += (4 + ((sizeof (double) * 3) * rng->Points));	/* # points + [x,y,z] array - interior ring */
1952 		      else if (geom->DimensionModel == GAIA_XY_Z_M)
1953 			  *size += (4 + ((sizeof (double) * 4) * rng->Points));	/* # points + [x,y,z,m] array - interior ring */
1954 		      else
1955 			  *size += (4 + ((sizeof (double) * 2) * rng->Points));	/* # points + [x,y] array - interior ring */
1956 		  }
1957 		polyg = polyg->Next;
1958 	    }
1959       };
1960     *result = malloc (*size);
1961     ptr = *result;
1962 /* and finally we build the BLOB */
1963     switch (type)
1964       {
1965       case GAIA_POINT:
1966 	  *ptr = GAIA_MARK_START;	/* START signature */
1967 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
1968 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
1969 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
1970 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
1971 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
1972 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
1973 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
1974 	  gaiaExport32 (ptr + 39, GAIA_POINT, 1, endian_arch);	/* class POINT */
1975 	  gaiaExport64 (ptr + 43, point->X, 1, endian_arch);	/* X */
1976 	  gaiaExport64 (ptr + 51, point->Y, 1, endian_arch);	/* Y */
1977 	  *(ptr + 59) = GAIA_MARK_END;	/* END signature */
1978 	  break;
1979       case GAIA_POINTZ:
1980 	  *ptr = GAIA_MARK_START;	/* START signature */
1981 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
1982 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
1983 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
1984 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
1985 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
1986 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
1987 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
1988 	  gaiaExport32 (ptr + 39, GAIA_POINTZ, 1, endian_arch);	/* class POINT XYZ */
1989 	  gaiaExport64 (ptr + 43, point->X, 1, endian_arch);	/* X */
1990 	  gaiaExport64 (ptr + 51, point->Y, 1, endian_arch);	/* Y */
1991 	  gaiaExport64 (ptr + 59, point->Z, 1, endian_arch);	/* Z */
1992 	  *(ptr + 67) = GAIA_MARK_END;	/* END signature */
1993 	  break;
1994       case GAIA_POINTM:
1995 	  *ptr = GAIA_MARK_START;	/* START signature */
1996 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
1997 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
1998 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
1999 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2000 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2001 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2002 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2003 	  gaiaExport32 (ptr + 39, GAIA_POINTM, 1, endian_arch);	/* class POINT XYM */
2004 	  gaiaExport64 (ptr + 43, point->X, 1, endian_arch);	/* X */
2005 	  gaiaExport64 (ptr + 51, point->Y, 1, endian_arch);	/* Y */
2006 	  gaiaExport64 (ptr + 59, point->M, 1, endian_arch);	/* M */
2007 	  *(ptr + 67) = GAIA_MARK_END;	/* END signature */
2008 	  break;
2009       case GAIA_POINTZM:
2010 	  *ptr = GAIA_MARK_START;	/* START signature */
2011 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2012 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2013 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2014 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2015 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2016 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2017 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2018 	  gaiaExport32 (ptr + 39, GAIA_POINTZM, 1, endian_arch);	/* class POINT XYZM */
2019 	  gaiaExport64 (ptr + 43, point->X, 1, endian_arch);	/* X */
2020 	  gaiaExport64 (ptr + 51, point->Y, 1, endian_arch);	/* Y */
2021 	  gaiaExport64 (ptr + 59, point->Z, 1, endian_arch);	/* M */
2022 	  gaiaExport64 (ptr + 67, point->M, 1, endian_arch);	/* Z */
2023 	  *(ptr + 75) = GAIA_MARK_END;	/* END signature */
2024 	  break;
2025       case GAIA_LINESTRING:
2026 	  *ptr = GAIA_MARK_START;	/* START signature */
2027 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2028 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2029 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2030 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2031 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2032 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2033 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2034 	  gaiaExport32 (ptr + 39, GAIA_LINESTRING, 1, endian_arch);	/* class LINESTRING */
2035 	  gaiaExport32 (ptr + 43, line->Points, 1, endian_arch);	/* # points */
2036 	  ptr += 47;
2037 	  for (iv = 0; iv < line->Points; iv++)
2038 	    {
2039 		gaiaGetPoint (line->Coords, iv, &x, &y);
2040 		gaiaExport64 (ptr, x, 1, endian_arch);
2041 		gaiaExport64 (ptr + 8, y, 1, endian_arch);
2042 		ptr += 16;
2043 	    }
2044 	  *ptr = GAIA_MARK_END;	/* END signature */
2045 	  break;
2046       case GAIA_LINESTRINGZ:
2047 	  *ptr = GAIA_MARK_START;	/* START signature */
2048 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2049 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2050 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2051 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2052 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2053 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2054 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2055 	  gaiaExport32 (ptr + 39, GAIA_LINESTRINGZ, 1, endian_arch);	/* class LINESTRING XYZ */
2056 	  gaiaExport32 (ptr + 43, line->Points, 1, endian_arch);	/* # points */
2057 	  ptr += 47;
2058 	  for (iv = 0; iv < line->Points; iv++)
2059 	    {
2060 		gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2061 		gaiaExport64 (ptr, x, 1, endian_arch);
2062 		gaiaExport64 (ptr + 8, y, 1, endian_arch);
2063 		gaiaExport64 (ptr + 16, z, 1, endian_arch);
2064 		ptr += 24;
2065 	    }
2066 	  *ptr = GAIA_MARK_END;	/* END signature */
2067 	  break;
2068       case GAIA_LINESTRINGM:
2069 	  *ptr = GAIA_MARK_START;	/* START signature */
2070 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2071 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2072 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2073 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2074 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2075 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2076 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2077 	  gaiaExport32 (ptr + 39, GAIA_LINESTRINGM, 1, endian_arch);	/* class LINESTRING XYM */
2078 	  gaiaExport32 (ptr + 43, line->Points, 1, endian_arch);	/* # points */
2079 	  ptr += 47;
2080 	  for (iv = 0; iv < line->Points; iv++)
2081 	    {
2082 		gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
2083 		gaiaExport64 (ptr, x, 1, endian_arch);
2084 		gaiaExport64 (ptr + 8, y, 1, endian_arch);
2085 		gaiaExport64 (ptr + 16, m, 1, endian_arch);
2086 		ptr += 24;
2087 	    }
2088 	  *ptr = GAIA_MARK_END;	/* END signature */
2089 	  break;
2090       case GAIA_LINESTRINGZM:
2091 	  *ptr = GAIA_MARK_START;	/* START signature */
2092 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2093 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2094 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2095 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2096 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2097 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2098 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2099 	  gaiaExport32 (ptr + 39, GAIA_LINESTRINGZM, 1, endian_arch);	/* class LINESTRING XYZM */
2100 	  gaiaExport32 (ptr + 43, line->Points, 1, endian_arch);	/* # points */
2101 	  ptr += 47;
2102 	  for (iv = 0; iv < line->Points; iv++)
2103 	    {
2104 		gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
2105 		gaiaExport64 (ptr, x, 1, endian_arch);
2106 		gaiaExport64 (ptr + 8, y, 1, endian_arch);
2107 		gaiaExport64 (ptr + 16, z, 1, endian_arch);
2108 		gaiaExport64 (ptr + 24, m, 1, endian_arch);
2109 		ptr += 32;
2110 	    }
2111 	  *ptr = GAIA_MARK_END;	/* END signature */
2112 	  break;
2113       case GAIA_POLYGON:
2114 	  *ptr = GAIA_MARK_START;	/* START signature */
2115 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2116 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2117 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2118 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2119 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2120 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2121 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2122 	  gaiaExport32 (ptr + 39, GAIA_POLYGON, 1, endian_arch);	/* class POLYGON */
2123 	  gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
2124 	  rng = polyg->Exterior;
2125 	  gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch);	/* # points - exterior ring */
2126 	  ptr += 51;
2127 	  for (iv = 0; iv < rng->Points; iv++)
2128 	    {
2129 		gaiaGetPoint (rng->Coords, iv, &x, &y);
2130 		gaiaExport64 (ptr, x, 1, endian_arch);	/* X - exterior ring */
2131 		gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - exterior ring */
2132 		ptr += 16;
2133 	    }
2134 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
2135 	    {
2136 		rng = polyg->Interiors + ib;
2137 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
2138 		ptr += 4;
2139 		for (iv = 0; iv < rng->Points; iv++)
2140 		  {
2141 		      gaiaGetPoint (rng->Coords, iv, &x, &y);
2142 		      gaiaExport64 (ptr, x, 1, endian_arch);	/* X - interior ring */
2143 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - interior ring */
2144 		      ptr += 16;
2145 		  }
2146 	    }
2147 	  *ptr = GAIA_MARK_END;	/* END signature */
2148 	  break;
2149       case GAIA_POLYGONZ:
2150 	  *ptr = GAIA_MARK_START;	/* START signature */
2151 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2152 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2153 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2154 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2155 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2156 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2157 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2158 	  gaiaExport32 (ptr + 39, GAIA_POLYGONZ, 1, endian_arch);	/* class POLYGON XYZ */
2159 	  gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
2160 	  rng = polyg->Exterior;
2161 	  gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch);	/* # points - exterior ring */
2162 	  ptr += 51;
2163 	  for (iv = 0; iv < rng->Points; iv++)
2164 	    {
2165 		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2166 		gaiaExport64 (ptr, x, 1, endian_arch);	/* X - exterior ring */
2167 		gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - exterior ring */
2168 		gaiaExport64 (ptr + 16, z, 1, endian_arch);	/* Z - exterior ring */
2169 		ptr += 24;
2170 	    }
2171 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
2172 	    {
2173 		rng = polyg->Interiors + ib;
2174 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
2175 		ptr += 4;
2176 		for (iv = 0; iv < rng->Points; iv++)
2177 		  {
2178 		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2179 		      gaiaExport64 (ptr, x, 1, endian_arch);	/* X - interior ring */
2180 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - interior ring */
2181 		      gaiaExport64 (ptr + 16, z, 1, endian_arch);	/* Z - interior ring */
2182 		      ptr += 24;
2183 		  }
2184 	    }
2185 	  *ptr = GAIA_MARK_END;	/* END signature */
2186 	  break;
2187       case GAIA_POLYGONM:
2188 	  *ptr = GAIA_MARK_START;	/* START signature */
2189 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2190 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2191 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2192 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2193 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2194 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2195 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2196 	  gaiaExport32 (ptr + 39, GAIA_POLYGONM, 1, endian_arch);	/* class POLYGON XYM */
2197 	  gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
2198 	  rng = polyg->Exterior;
2199 	  gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch);	/* # points - exterior ring */
2200 	  ptr += 51;
2201 	  for (iv = 0; iv < rng->Points; iv++)
2202 	    {
2203 		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2204 		gaiaExport64 (ptr, x, 1, endian_arch);	/* X - exterior ring */
2205 		gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - exterior ring */
2206 		gaiaExport64 (ptr + 16, m, 1, endian_arch);	/* M - exterior ring */
2207 		ptr += 24;
2208 	    }
2209 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
2210 	    {
2211 		rng = polyg->Interiors + ib;
2212 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
2213 		ptr += 4;
2214 		for (iv = 0; iv < rng->Points; iv++)
2215 		  {
2216 		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2217 		      gaiaExport64 (ptr, x, 1, endian_arch);	/* X - interior ring */
2218 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - interior ring */
2219 		      gaiaExport64 (ptr + 16, m, 1, endian_arch);	/* M - interior ring */
2220 		      ptr += 24;
2221 		  }
2222 	    }
2223 	  *ptr = GAIA_MARK_END;	/* END signature */
2224 	  break;
2225       case GAIA_POLYGONZM:
2226 	  *ptr = GAIA_MARK_START;	/* START signature */
2227 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2228 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2229 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2230 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2231 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2232 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2233 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2234 	  gaiaExport32 (ptr + 39, GAIA_POLYGONZM, 1, endian_arch);	/* class POLYGON */
2235 	  gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
2236 	  rng = polyg->Exterior;
2237 	  gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch);	/* # points - exterior ring */
2238 	  ptr += 51;
2239 	  for (iv = 0; iv < rng->Points; iv++)
2240 	    {
2241 		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2242 		gaiaExport64 (ptr, x, 1, endian_arch);	/* X - exterior ring */
2243 		gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - exterior ring */
2244 		gaiaExport64 (ptr + 16, z, 1, endian_arch);	/* Z - exterior ring */
2245 		gaiaExport64 (ptr + 24, m, 1, endian_arch);	/* M - exterior ring */
2246 		ptr += 32;
2247 	    }
2248 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
2249 	    {
2250 		rng = polyg->Interiors + ib;
2251 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
2252 		ptr += 4;
2253 		for (iv = 0; iv < rng->Points; iv++)
2254 		  {
2255 		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2256 		      gaiaExport64 (ptr, x, 1, endian_arch);	/* X - interior ring */
2257 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - interior ring */
2258 		      gaiaExport64 (ptr + 16, z, 1, endian_arch);	/* Z - exterior ring */
2259 		      gaiaExport64 (ptr + 24, m, 1, endian_arch);	/* M - exterior ring */
2260 		      ptr += 32;
2261 		  }
2262 	    }
2263 	  *ptr = GAIA_MARK_END;	/* END signature */
2264 	  break;
2265       default:
2266 	  /* this one is a MULTIxxxx or a GEOMETRYCOLLECTION - building the main header */
2267 	  *ptr = GAIA_MARK_START;	/* START signature */
2268 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2269 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2270 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2271 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2272 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2273 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2274 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2275 	  gaiaExport32 (ptr + 39, type, 1, endian_arch);	/* geometric class */
2276 	  gaiaExport32 (ptr + 43, entities, 1, endian_arch);	/* # entities */
2277 	  ptr += 47;
2278 	  point = geom->FirstPoint;
2279 	  while (point)
2280 	    {
2281 		*ptr = GAIA_MARK_ENTITY;	/* ENTITY signature */
2282 		if (geom->DimensionModel == GAIA_XY_Z)
2283 		  {
2284 		      gaiaExport32 (ptr + 1, GAIA_POINTZ, 1, endian_arch);	/* class POINT XYZ */
2285 		      gaiaExport64 (ptr + 5, point->X, 1, endian_arch);	/* X */
2286 		      gaiaExport64 (ptr + 13, point->Y, 1, endian_arch);	/* Y */
2287 		      gaiaExport64 (ptr + 21, point->Z, 1, endian_arch);	/* Z */
2288 		      ptr += 29;
2289 		  }
2290 		else if (geom->DimensionModel == GAIA_XY_M)
2291 		  {
2292 		      gaiaExport32 (ptr + 1, GAIA_POINTM, 1, endian_arch);	/* class POINT XYM */
2293 		      gaiaExport64 (ptr + 5, point->X, 1, endian_arch);	/* X */
2294 		      gaiaExport64 (ptr + 13, point->Y, 1, endian_arch);	/* Y */
2295 		      gaiaExport64 (ptr + 21, point->M, 1, endian_arch);	/* M */
2296 		      ptr += 29;
2297 		  }
2298 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2299 		  {
2300 		      gaiaExport32 (ptr + 1, GAIA_POINTZM, 1, endian_arch);	/* class POINT XYZM */
2301 		      gaiaExport64 (ptr + 5, point->X, 1, endian_arch);	/* X */
2302 		      gaiaExport64 (ptr + 13, point->Y, 1, endian_arch);	/* Y */
2303 		      gaiaExport64 (ptr + 21, point->Z, 1, endian_arch);	/* Z */
2304 		      gaiaExport64 (ptr + 29, point->M, 1, endian_arch);	/* M */
2305 		      ptr += 37;
2306 		  }
2307 		else
2308 		  {
2309 		      gaiaExport32 (ptr + 1, GAIA_POINT, 1, endian_arch);	/* class POINT */
2310 		      gaiaExport64 (ptr + 5, point->X, 1, endian_arch);	/* X */
2311 		      gaiaExport64 (ptr + 13, point->Y, 1, endian_arch);	/* Y */
2312 		      ptr += 21;
2313 		  }
2314 		point = point->Next;
2315 	    }
2316 	  line = geom->FirstLinestring;
2317 	  while (line)
2318 	    {
2319 		*ptr = GAIA_MARK_ENTITY;	/* ENTITY signature */
2320 		if (geom->DimensionModel == GAIA_XY_Z)
2321 		    gaiaExport32 (ptr + 1, GAIA_LINESTRINGZ, 1, endian_arch);	/* class LINESTRING XYZ */
2322 		else if (geom->DimensionModel == GAIA_XY_M)
2323 		    gaiaExport32 (ptr + 1, GAIA_LINESTRINGM, 1, endian_arch);	/* class LINESTRING XYM */
2324 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2325 		    gaiaExport32 (ptr + 1, GAIA_LINESTRINGZM, 1, endian_arch);	/* class LINESTRING XYZM */
2326 		else
2327 		    gaiaExport32 (ptr + 1, GAIA_LINESTRING, 1, endian_arch);	/* class LINESTRING */
2328 		gaiaExport32 (ptr + 5, line->Points, 1, endian_arch);	/* # points */
2329 		ptr += 9;
2330 		for (iv = 0; iv < line->Points; iv++)
2331 		  {
2332 		      if (geom->DimensionModel == GAIA_XY_Z)
2333 			{
2334 			    gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2335 			}
2336 		      else if (geom->DimensionModel == GAIA_XY_M)
2337 			{
2338 			    gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
2339 			}
2340 		      else if (geom->DimensionModel == GAIA_XY_Z_M)
2341 			{
2342 			    gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
2343 			}
2344 		      else
2345 			{
2346 			    gaiaGetPoint (line->Coords, iv, &x, &y);
2347 			}
2348 		      gaiaExport64 (ptr, x, 1, endian_arch);	/* X */
2349 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y */
2350 		      ptr += 16;
2351 		      if (geom->DimensionModel == GAIA_XY_Z)
2352 			{
2353 			    gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
2354 			    ptr += 8;
2355 			}
2356 		      if (geom->DimensionModel == GAIA_XY_M)
2357 			{
2358 			    gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
2359 			    ptr += 8;
2360 			}
2361 		      if (geom->DimensionModel == GAIA_XY_Z_M)
2362 			{
2363 			    gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
2364 			    gaiaExport64 (ptr + 8, m, 1, endian_arch);	/* M */
2365 			    ptr += 16;
2366 			}
2367 		  }
2368 		line = line->Next;
2369 	    }
2370 	  polyg = geom->FirstPolygon;
2371 	  while (polyg)
2372 	    {
2373 		*ptr = GAIA_MARK_ENTITY;	/* ENTITY signature */
2374 		if (geom->DimensionModel == GAIA_XY_Z)
2375 		    gaiaExport32 (ptr + 1, GAIA_POLYGONZ, 1, endian_arch);	/* class POLYGON XYZ */
2376 		else if (geom->DimensionModel == GAIA_XY_M)
2377 		    gaiaExport32 (ptr + 1, GAIA_POLYGONM, 1, endian_arch);	/* class POLYGON XYM */
2378 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2379 		    gaiaExport32 (ptr + 1, GAIA_POLYGONZM, 1, endian_arch);	/* class POLYGON XYZM */
2380 		else
2381 		    gaiaExport32 (ptr + 1, GAIA_POLYGON, 1, endian_arch);	/* class POLYGON */
2382 		gaiaExport32 (ptr + 5, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
2383 		rng = polyg->Exterior;
2384 		gaiaExport32 (ptr + 9, rng->Points, 1, endian_arch);	/* # points - exterior ring */
2385 		ptr += 13;
2386 		for (iv = 0; iv < rng->Points; iv++)
2387 		  {
2388 		      if (geom->DimensionModel == GAIA_XY_Z)
2389 			{
2390 			    gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2391 			}
2392 		      else if (geom->DimensionModel == GAIA_XY_M)
2393 			{
2394 			    gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2395 			}
2396 		      else if (geom->DimensionModel == GAIA_XY_Z_M)
2397 			{
2398 			    gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2399 			}
2400 		      else
2401 			{
2402 			    gaiaGetPoint (rng->Coords, iv, &x, &y);
2403 			}
2404 		      gaiaExport64 (ptr, x, 1, endian_arch);	/* X - exterior ring */
2405 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - exterior ring */
2406 		      ptr += 16;
2407 		      if (geom->DimensionModel == GAIA_XY_Z)
2408 			{
2409 			    gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
2410 			    ptr += 8;
2411 			}
2412 		      if (geom->DimensionModel == GAIA_XY_M)
2413 			{
2414 			    gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
2415 			    ptr += 8;
2416 			}
2417 		      if (geom->DimensionModel == GAIA_XY_Z_M)
2418 			{
2419 			    gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
2420 			    gaiaExport64 (ptr + 8, m, 1, endian_arch);	/* M */
2421 			    ptr += 16;
2422 			}
2423 		  }
2424 		for (ib = 0; ib < polyg->NumInteriors; ib++)
2425 		  {
2426 		      rng = polyg->Interiors + ib;
2427 		      gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
2428 		      ptr += 4;
2429 		      for (iv = 0; iv < rng->Points; iv++)
2430 			{
2431 			    if (geom->DimensionModel == GAIA_XY_Z)
2432 			      {
2433 				  gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2434 			      }
2435 			    else if (geom->DimensionModel == GAIA_XY_M)
2436 			      {
2437 				  gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2438 			      }
2439 			    else if (geom->DimensionModel == GAIA_XY_Z_M)
2440 			      {
2441 				  gaiaGetPointXYZM (rng->Coords, iv, &x, &y,
2442 						    &z, &m);
2443 			      }
2444 			    else
2445 			      {
2446 				  gaiaGetPoint (rng->Coords, iv, &x, &y);
2447 			      }
2448 			    gaiaExport64 (ptr, x, 1, endian_arch);	/* X - interior ring */
2449 			    gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - interior ring */
2450 			    ptr += 16;
2451 			    if (geom->DimensionModel == GAIA_XY_Z)
2452 			      {
2453 				  gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
2454 				  ptr += 8;
2455 			      }
2456 			    if (geom->DimensionModel == GAIA_XY_M)
2457 			      {
2458 				  gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
2459 				  ptr += 8;
2460 			      }
2461 			    if (geom->DimensionModel == GAIA_XY_Z_M)
2462 			      {
2463 				  gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
2464 				  gaiaExport64 (ptr + 8, m, 1, endian_arch);	/* M */
2465 				  ptr += 16;
2466 			      }
2467 			}
2468 		  }
2469 		polyg = polyg->Next;
2470 	    }
2471 	  *ptr = GAIA_MARK_END;	/* END signature */
2472       };
2473 }
2474 
2475 GAIAGEO_DECLARE void
gaiaToSpatiaLiteBlobWkb(gaiaGeomCollPtr geom,unsigned char ** result,int * size)2476 gaiaToSpatiaLiteBlobWkb (gaiaGeomCollPtr geom, unsigned char **result,
2477 			 int *size)
2478 {
2479 /*
2480 * builds the SpatiaLite BLOB representation for this GEOMETRY
2481 * convenience method - always disabling GPKG compatibility Modes
2482 */
2483     gaiaToSpatiaLiteBlobWkbEx (geom, result, size, 0);
2484 }
2485 
2486 GAIAGEO_DECLARE void
gaiaToCompressedBlobWkb(gaiaGeomCollPtr geom,unsigned char ** result,int * size)2487 gaiaToCompressedBlobWkb (gaiaGeomCollPtr geom, unsigned char **result,
2488 			 int *size)
2489 {
2490 /*
2491 / builds the SpatiaLite BLOB representation for this GEOMETRY
2492 / geometry-compression will be applied to LINESTRINGs and RINGs
2493 */
2494     int ib;
2495     int iv;
2496     double x;
2497     double y;
2498     double z;
2499     double m;
2500     double last_x = 0.0;
2501     double last_y = 0.0;
2502     double last_z = 0.0;
2503     float fx;
2504     float fy;
2505     float fz;
2506     int entities = 0;
2507     int n_points = 0;
2508     int n_linestrings = 0;
2509     int n_polygons = 0;
2510     int type;
2511     unsigned char *ptr;
2512     gaiaPointPtr pt;
2513     gaiaLinestringPtr ln;
2514     gaiaPolygonPtr pg;
2515     gaiaRingPtr rng;
2516     gaiaPointPtr point = NULL;
2517     gaiaLinestringPtr line = NULL;
2518     gaiaPolygonPtr polyg = NULL;
2519     int endian_arch = gaiaEndianArch ();
2520     gaiaMbrGeometry (geom);
2521 /* how many entities, and of what kind, do we have ? */
2522     pt = geom->FirstPoint;
2523     while (pt)
2524       {
2525 	  point = pt;
2526 	  entities++;
2527 	  n_points++;
2528 	  pt = pt->Next;
2529       }
2530     ln = geom->FirstLinestring;
2531     while (ln)
2532       {
2533 	  line = ln;
2534 	  entities++;
2535 	  n_linestrings++;
2536 	  ln = ln->Next;
2537       }
2538     pg = geom->FirstPolygon;
2539     while (pg)
2540       {
2541 	  polyg = pg;
2542 	  entities++;
2543 	  n_polygons++;
2544 	  pg = pg->Next;
2545       }
2546     *size = 0;
2547     *result = NULL;
2548     if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
2549 	return;
2550 /* ok, we can determine the geometry class */
2551     if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
2552       {
2553 	  if (geom->DeclaredType == GAIA_MULTIPOINT)
2554 	    {
2555 		if (geom->DimensionModel == GAIA_XY_Z)
2556 		    type = GAIA_MULTIPOINTZ;
2557 		else if (geom->DimensionModel == GAIA_XY_M)
2558 		    type = GAIA_MULTIPOINTM;
2559 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2560 		    type = GAIA_MULTIPOINTZM;
2561 		else
2562 		    type = GAIA_MULTIPOINT;
2563 	    }
2564 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2565 	    {
2566 		if (geom->DimensionModel == GAIA_XY_Z)
2567 		    type = GAIA_GEOMETRYCOLLECTIONZ;
2568 		else if (geom->DimensionModel == GAIA_XY_M)
2569 		    type = GAIA_GEOMETRYCOLLECTIONM;
2570 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2571 		    type = GAIA_GEOMETRYCOLLECTIONZM;
2572 		else
2573 		    type = GAIA_GEOMETRYCOLLECTION;
2574 	    }
2575 	  else
2576 	    {
2577 		if (geom->DimensionModel == GAIA_XY_Z)
2578 		    type = GAIA_POINTZ;
2579 		else if (geom->DimensionModel == GAIA_XY_M)
2580 		    type = GAIA_POINTM;
2581 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2582 		    type = GAIA_POINTZM;
2583 		else
2584 		    type = GAIA_POINT;
2585 	    }
2586       }
2587     else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
2588       {
2589 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2590 	    {
2591 		if (geom->DimensionModel == GAIA_XY_Z)
2592 		    type = GAIA_GEOMETRYCOLLECTIONZ;
2593 		else if (geom->DimensionModel == GAIA_XY_M)
2594 		    type = GAIA_GEOMETRYCOLLECTIONM;
2595 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2596 		    type = GAIA_GEOMETRYCOLLECTIONZM;
2597 		else
2598 		    type = GAIA_GEOMETRYCOLLECTION;
2599 	    }
2600 	  else
2601 	    {
2602 		if (geom->DimensionModel == GAIA_XY_Z)
2603 		    type = GAIA_MULTIPOINTZ;
2604 		else if (geom->DimensionModel == GAIA_XY_M)
2605 		    type = GAIA_MULTIPOINTM;
2606 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2607 		    type = GAIA_MULTIPOINTZM;
2608 		else
2609 		    type = GAIA_MULTIPOINT;
2610 	    }
2611       }
2612     else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
2613       {
2614 	  if (geom->DeclaredType == GAIA_MULTILINESTRING)
2615 	    {
2616 		if (geom->DimensionModel == GAIA_XY_Z)
2617 		    type = GAIA_MULTILINESTRINGZ;
2618 		else if (geom->DimensionModel == GAIA_XY_M)
2619 		    type = GAIA_MULTILINESTRINGM;
2620 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2621 		    type = GAIA_MULTILINESTRINGZM;
2622 		else
2623 		    type = GAIA_MULTILINESTRING;
2624 	    }
2625 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2626 	    {
2627 		if (geom->DimensionModel == GAIA_XY_Z)
2628 		    type = GAIA_GEOMETRYCOLLECTIONZ;
2629 		else if (geom->DimensionModel == GAIA_XY_M)
2630 		    type = GAIA_GEOMETRYCOLLECTIONM;
2631 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2632 		    type = GAIA_GEOMETRYCOLLECTIONZM;
2633 		else
2634 		    type = GAIA_GEOMETRYCOLLECTION;
2635 	    }
2636 	  else
2637 	    {
2638 		if (geom->DimensionModel == GAIA_XY_Z)
2639 		    type = GAIA_LINESTRINGZ;
2640 		else if (geom->DimensionModel == GAIA_XY_M)
2641 		    type = GAIA_LINESTRINGM;
2642 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2643 		    type = GAIA_LINESTRINGZM;
2644 		else
2645 		    type = GAIA_LINESTRING;
2646 	    }
2647       }
2648     else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
2649       {
2650 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2651 	    {
2652 		if (geom->DimensionModel == GAIA_XY_Z)
2653 		    type = GAIA_GEOMETRYCOLLECTIONZ;
2654 		else if (geom->DimensionModel == GAIA_XY_M)
2655 		    type = GAIA_GEOMETRYCOLLECTIONM;
2656 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2657 		    type = GAIA_GEOMETRYCOLLECTIONZM;
2658 		else
2659 		    type = GAIA_GEOMETRYCOLLECTION;
2660 	    }
2661 	  else
2662 	    {
2663 		if (geom->DimensionModel == GAIA_XY_Z)
2664 		    type = GAIA_MULTILINESTRINGZ;
2665 		else if (geom->DimensionModel == GAIA_XY_M)
2666 		    type = GAIA_MULTILINESTRINGM;
2667 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2668 		    type = GAIA_MULTILINESTRINGZM;
2669 		else
2670 		    type = GAIA_MULTILINESTRING;
2671 	    }
2672       }
2673     else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
2674       {
2675 	  if (geom->DeclaredType == GAIA_MULTIPOLYGON)
2676 	    {
2677 		if (geom->DimensionModel == GAIA_XY_Z)
2678 		    type = GAIA_MULTIPOLYGONZ;
2679 		else if (geom->DimensionModel == GAIA_XY_M)
2680 		    type = GAIA_MULTIPOLYGONM;
2681 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2682 		    type = GAIA_MULTIPOLYGONZM;
2683 		else
2684 		    type = GAIA_MULTIPOLYGON;
2685 	    }
2686 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2687 	    {
2688 		if (geom->DimensionModel == GAIA_XY_Z)
2689 		    type = GAIA_GEOMETRYCOLLECTIONZ;
2690 		else if (geom->DimensionModel == GAIA_XY_M)
2691 		    type = GAIA_GEOMETRYCOLLECTIONM;
2692 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2693 		    type = GAIA_GEOMETRYCOLLECTIONZM;
2694 		else
2695 		    type = GAIA_GEOMETRYCOLLECTION;
2696 	    }
2697 	  else
2698 	    {
2699 		if (geom->DimensionModel == GAIA_XY_Z)
2700 		    type = GAIA_POLYGONZ;
2701 		else if (geom->DimensionModel == GAIA_XY_M)
2702 		    type = GAIA_POLYGONM;
2703 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2704 		    type = GAIA_POLYGONZM;
2705 		else
2706 		    type = GAIA_POLYGON;
2707 	    }
2708       }
2709     else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
2710       {
2711 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
2712 	    {
2713 		if (geom->DimensionModel == GAIA_XY_Z)
2714 		    type = GAIA_GEOMETRYCOLLECTIONZ;
2715 		else if (geom->DimensionModel == GAIA_XY_M)
2716 		    type = GAIA_GEOMETRYCOLLECTIONM;
2717 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2718 		    type = GAIA_GEOMETRYCOLLECTIONZM;
2719 		else
2720 		    type = GAIA_GEOMETRYCOLLECTION;
2721 	    }
2722 	  else
2723 	    {
2724 		if (geom->DimensionModel == GAIA_XY_Z)
2725 		    type = GAIA_MULTIPOLYGONZ;
2726 		else if (geom->DimensionModel == GAIA_XY_M)
2727 		    type = GAIA_MULTIPOLYGONM;
2728 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2729 		    type = GAIA_MULTIPOLYGONZM;
2730 		else
2731 		    type = GAIA_MULTIPOLYGON;
2732 	    }
2733       }
2734     else
2735       {
2736 	  if (geom->DimensionModel == GAIA_XY_Z)
2737 	      type = GAIA_GEOMETRYCOLLECTIONZ;
2738 	  else if (geom->DimensionModel == GAIA_XY_M)
2739 	      type = GAIA_GEOMETRYCOLLECTIONM;
2740 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
2741 	      type = GAIA_GEOMETRYCOLLECTIONZM;
2742 	  else
2743 	      type = GAIA_GEOMETRYCOLLECTION;
2744       }
2745 /* and now we compute the size of BLOB */
2746     *size = 44;			/* header size */
2747     switch (type)
2748       {
2749       case GAIA_POINT:
2750 	  *size += (sizeof (double) * 2);	/* [x,y] coords */
2751 	  break;
2752       case GAIA_POINTZ:
2753 	  *size += (sizeof (double) * 3);	/* [x,y,z] coords */
2754 	  break;
2755       case GAIA_POINTM:
2756 	  *size += (sizeof (double) * 3);	/* [x,y,m] coords */
2757 	  break;
2758       case GAIA_POINTZM:
2759 	  *size += (sizeof (double) * 4);	/* [x,y,z,m] coords */
2760 	  break;
2761       case GAIA_LINESTRING:
2762 	  *size += (4 + (8 * line->Points) + 16);	/* # points + [x,y] for each vertex */
2763 	  break;
2764       case GAIA_LINESTRINGZ:
2765 	  *size += (4 + (12 * line->Points) + 24);	/* # points + [x,y,z] for each vertex */
2766 	  break;
2767       case GAIA_LINESTRINGM:
2768 	  *size += (4 + (16 * line->Points) + 16);	/* # points + [x,y,m] for each vertex */
2769 	  break;
2770       case GAIA_LINESTRINGZM:
2771 	  *size += (4 + (20 * line->Points) + 24);	/* # points + [x,y,z,m] for each vertex */
2772 	  break;
2773       case GAIA_POLYGON:
2774 	  rng = polyg->Exterior;
2775 	  *size += (8 + (8 * rng->Points) + 16);	/* # rings + # points + [x.y] array - exterior ring */
2776 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
2777 	    {
2778 		rng = polyg->Interiors + ib;
2779 		*size += (4 + (8 * rng->Points) + 16);	/* # points + [x,y] array - interior ring */
2780 	    }
2781 	  break;
2782       case GAIA_POLYGONZ:
2783 	  rng = polyg->Exterior;
2784 	  *size += (8 + (12 * rng->Points) + 24);	/* # rings + # points + [x,y,z] array - exterior ring */
2785 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
2786 	    {
2787 		rng = polyg->Interiors + ib;
2788 		*size += (4 + (12 * rng->Points) + 24);	/* # points + [x,y,z] array - interior ring */
2789 	    }
2790 	  break;
2791       case GAIA_POLYGONM:
2792 	  rng = polyg->Exterior;
2793 	  *size += (8 + (16 * rng->Points) + 16);	/* # rings + # points + [x,y,m] array - exterior ring */
2794 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
2795 	    {
2796 		rng = polyg->Interiors + ib;
2797 		*size += (4 + (16 * rng->Points) + 16);	/* # points + [x,y,m] array - interior ring */
2798 	    }
2799 	  break;
2800       case GAIA_POLYGONZM:
2801 	  rng = polyg->Exterior;
2802 	  *size += (8 + (20 * rng->Points) + 24);	/* # rings + # points + [x,y,z,m] array - exterior ring */
2803 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
2804 	    {
2805 		rng = polyg->Interiors + ib;
2806 		*size += (4 + (20 * rng->Points) + 24);	/* # points + [x,y,z,m] array - interior ring */
2807 	    }
2808 	  break;
2809       default:
2810 	  /* this one is not a simple geometry; should be a MULTIxxxx or a GEOMETRYCOLLECTION */
2811 	  *size += 4;		/* # entities */
2812 	  point = geom->FirstPoint;
2813 	  while (point)
2814 	    {
2815 		*size += 5;	/* entity header */
2816 		if (geom->DimensionModel == GAIA_XY_Z
2817 		    || geom->DimensionModel == GAIA_XY_M)
2818 		    *size += (sizeof (double) * 3);	/* three doubles for each POINT */
2819 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2820 		    *size += (sizeof (double) * 4);	/* four doubles for each POINT */
2821 		else
2822 		    *size += (sizeof (double) * 2);	/* two doubles for each POINT */
2823 		point = point->Next;
2824 	    }
2825 	  line = geom->FirstLinestring;
2826 	  while (line)
2827 	    {
2828 		*size += 5;	/* entity header */
2829 		if (geom->DimensionModel == GAIA_XY_Z)
2830 		    *size += (4 + (12 * line->Points) + 24);	/* # points + [x,y,z] for each vertex */
2831 		else if (geom->DimensionModel == GAIA_XY_M)
2832 		    *size += (4 + (16 * line->Points) + 16);	/* # points + [x,y,m] for each vertex */
2833 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2834 		    *size += (4 + (20 * line->Points) + 24);	/* # points + [x,y,z,m] for each vertex */
2835 		else
2836 		    *size += (4 + (8 * line->Points) + 16);	/* # points + [x,y] for each vertex */
2837 		line = line->Next;
2838 	    }
2839 	  polyg = geom->FirstPolygon;
2840 	  while (polyg)
2841 	    {
2842 		*size += 5;	/* entity header */
2843 		rng = polyg->Exterior;
2844 		if (geom->DimensionModel == GAIA_XY_Z)
2845 		    *size += (8 + (12 * rng->Points) + 24);	/* # rings + # points + [x,y,z] array - exterior ring */
2846 		else if (geom->DimensionModel == GAIA_XY_M)
2847 		    *size += (8 + (16 * rng->Points) + 16);	/* # rings + # points + [x,y,m] array - exterior ring */
2848 		else if (geom->DimensionModel == GAIA_XY_Z_M)
2849 		    *size += (8 + (20 * rng->Points) + 24);	/* # rings + # points + [x,y,z,m] array - exterior ring */
2850 		else
2851 		    *size += (8 + (8 * rng->Points) + 16);	/* # rings + # points + [x,y] array - exterior ring */
2852 		for (ib = 0; ib < polyg->NumInteriors; ib++)
2853 		  {
2854 		      rng = polyg->Interiors + ib;
2855 		      if (geom->DimensionModel == GAIA_XY_Z)
2856 			  *size += (4 + (12 * rng->Points) + 24);	/* # points + [x,y,z] array - interior ring */
2857 		      else if (geom->DimensionModel == GAIA_XY_M)
2858 			  *size += (4 + (16 * rng->Points) + 16);	/* # points + [x,y,m] array - interior ring */
2859 		      else if (geom->DimensionModel == GAIA_XY_Z_M)
2860 			  *size += (4 + (20 * rng->Points) + 24);	/* # points + [x,y,z,m] array - interior ring */
2861 		      else
2862 			  *size += (4 + (8 * rng->Points) + 16);	/* # points + [x,y] array - interior ring */
2863 		  }
2864 		polyg = polyg->Next;
2865 	    }
2866       };
2867     *result = malloc (*size);
2868     ptr = *result;
2869 /* and finally we build the BLOB */
2870     switch (type)
2871       {
2872       case GAIA_POINT:
2873 	  *ptr = GAIA_MARK_START;	/* START signature */
2874 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2875 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2876 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2877 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2878 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2879 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2880 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2881 	  gaiaExport32 (ptr + 39, GAIA_POINT, 1, endian_arch);	/* class POINT */
2882 	  gaiaExport64 (ptr + 43, point->X, 1, endian_arch);	/* X */
2883 	  gaiaExport64 (ptr + 51, point->Y, 1, endian_arch);	/* Y */
2884 	  *(ptr + 59) = GAIA_MARK_END;	/* END signature */
2885 	  break;
2886       case GAIA_POINTZ:
2887 	  *ptr = GAIA_MARK_START;	/* START signature */
2888 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2889 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2890 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2891 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2892 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2893 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2894 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2895 	  gaiaExport32 (ptr + 39, GAIA_POINTZ, 1, endian_arch);	/* class POINT XYZ */
2896 	  gaiaExport64 (ptr + 43, point->X, 1, endian_arch);	/* X */
2897 	  gaiaExport64 (ptr + 51, point->Y, 1, endian_arch);	/* Y */
2898 	  gaiaExport64 (ptr + 59, point->Z, 1, endian_arch);	/* Z */
2899 	  *(ptr + 67) = GAIA_MARK_END;	/* END signature */
2900 	  break;
2901       case GAIA_POINTM:
2902 	  *ptr = GAIA_MARK_START;	/* START signature */
2903 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2904 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2905 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2906 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2907 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2908 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2909 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2910 	  gaiaExport32 (ptr + 39, GAIA_POINTM, 1, endian_arch);	/* class POINT XYM */
2911 	  gaiaExport64 (ptr + 43, point->X, 1, endian_arch);	/* X */
2912 	  gaiaExport64 (ptr + 51, point->Y, 1, endian_arch);	/* Y */
2913 	  gaiaExport64 (ptr + 59, point->M, 1, endian_arch);	/* M */
2914 	  *(ptr + 67) = GAIA_MARK_END;	/* END signature */
2915 	  break;
2916       case GAIA_POINTZM:
2917 	  *ptr = GAIA_MARK_START;	/* START signature */
2918 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2919 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2920 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2921 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2922 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2923 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2924 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2925 	  gaiaExport32 (ptr + 39, GAIA_POINTZM, 1, endian_arch);	/* class POINT XYZM */
2926 	  gaiaExport64 (ptr + 43, point->X, 1, endian_arch);	/* X */
2927 	  gaiaExport64 (ptr + 51, point->Y, 1, endian_arch);	/* Y */
2928 	  gaiaExport64 (ptr + 59, point->Z, 1, endian_arch);	/* M */
2929 	  gaiaExport64 (ptr + 67, point->M, 1, endian_arch);	/* Z */
2930 	  *(ptr + 75) = GAIA_MARK_END;	/* END signature */
2931 	  break;
2932       case GAIA_LINESTRING:
2933 	  *ptr = GAIA_MARK_START;	/* START signature */
2934 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2935 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2936 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2937 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2938 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2939 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2940 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2941 	  gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRING, 1, endian_arch);	/* class LINESTRING */
2942 	  gaiaExport32 (ptr + 43, line->Points, 1, endian_arch);	/* # points */
2943 	  ptr += 47;
2944 	  for (iv = 0; iv < line->Points; iv++)
2945 	    {
2946 		gaiaGetPoint (line->Coords, iv, &x, &y);
2947 		if (iv == 0 || iv == (line->Points - 1))
2948 		  {
2949 		      /* first and last vertices are uncompressed */
2950 		      gaiaExport64 (ptr, x, 1, endian_arch);
2951 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);
2952 		      ptr += 16;
2953 		  }
2954 		else
2955 		  {
2956 		      /* compressing any other intermediate vertex */
2957 		      fx = (float) (x - last_x);
2958 		      fy = (float) (y - last_y);
2959 		      gaiaExportF32 (ptr, fx, 1, endian_arch);
2960 		      gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
2961 		      ptr += 8;
2962 		  }
2963 		last_x = x;
2964 		last_y = y;
2965 	    }
2966 	  *ptr = GAIA_MARK_END;	/* END signature */
2967 	  break;
2968       case GAIA_LINESTRINGZ:
2969 	  *ptr = GAIA_MARK_START;	/* START signature */
2970 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
2971 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
2972 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
2973 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
2974 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
2975 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
2976 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
2977 	  gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRINGZ, 1, endian_arch);	/* class LINESTRING XYZ */
2978 	  gaiaExport32 (ptr + 43, line->Points, 1, endian_arch);	/* # points */
2979 	  ptr += 47;
2980 	  for (iv = 0; iv < line->Points; iv++)
2981 	    {
2982 		gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2983 		if (iv == 0 || iv == (line->Points - 1))
2984 		  {
2985 		      /* first and last vertices are uncompressed */
2986 		      gaiaExport64 (ptr, x, 1, endian_arch);
2987 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);
2988 		      gaiaExport64 (ptr + 16, z, 1, endian_arch);
2989 		      ptr += 24;
2990 		  }
2991 		else
2992 		  {
2993 		      /* compressing any other intermediate vertex */
2994 		      fx = (float) (x - last_x);
2995 		      fy = (float) (y - last_y);
2996 		      fz = (float) (z - last_z);
2997 		      gaiaExportF32 (ptr, fx, 1, endian_arch);
2998 		      gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
2999 		      gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3000 		      ptr += 12;
3001 		  }
3002 		last_x = x;
3003 		last_y = y;
3004 		last_z = z;
3005 	    }
3006 	  *ptr = GAIA_MARK_END;	/* END signature */
3007 	  break;
3008       case GAIA_LINESTRINGM:
3009 	  *ptr = GAIA_MARK_START;	/* START signature */
3010 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
3011 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
3012 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
3013 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
3014 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
3015 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
3016 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
3017 	  gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRINGM, 1, endian_arch);	/* class LINESTRING XYM */
3018 	  gaiaExport32 (ptr + 43, line->Points, 1, endian_arch);	/* # points */
3019 	  ptr += 47;
3020 	  for (iv = 0; iv < line->Points; iv++)
3021 	    {
3022 		gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
3023 		if (iv == 0 || iv == (line->Points - 1))
3024 		  {
3025 		      /* first and last vertices are uncompressed */
3026 		      gaiaExport64 (ptr, x, 1, endian_arch);
3027 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);
3028 		      gaiaExport64 (ptr + 16, m, 1, endian_arch);
3029 		      ptr += 24;
3030 		  }
3031 		else
3032 		  {
3033 		      /* compressing any other intermediate vertex */
3034 		      fx = (float) (x - last_x);
3035 		      fy = (float) (y - last_y);
3036 		      gaiaExportF32 (ptr, fx, 1, endian_arch);
3037 		      gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3038 		      gaiaExport64 (ptr + 8, m, 1, endian_arch);
3039 		      ptr += 16;
3040 		  }
3041 		last_x = x;
3042 		last_y = y;
3043 	    }
3044 	  *ptr = GAIA_MARK_END;	/* END signature */
3045 	  break;
3046       case GAIA_LINESTRINGZM:
3047 	  *ptr = GAIA_MARK_START;	/* START signature */
3048 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
3049 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
3050 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
3051 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
3052 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
3053 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
3054 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
3055 	  gaiaExport32 (ptr + 39, GAIA_COMPRESSED_LINESTRINGZM, 1, endian_arch);	/* class LINESTRING XYZM */
3056 	  gaiaExport32 (ptr + 43, line->Points, 1, endian_arch);	/* # points */
3057 	  ptr += 47;
3058 	  for (iv = 0; iv < line->Points; iv++)
3059 	    {
3060 		gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
3061 		if (iv == 0 || iv == (line->Points - 1))
3062 		  {
3063 		      /* first and last vertices are uncompressed */
3064 		      gaiaExport64 (ptr, x, 1, endian_arch);
3065 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);
3066 		      gaiaExport64 (ptr + 16, z, 1, endian_arch);
3067 		      gaiaExport64 (ptr + 24, m, 1, endian_arch);
3068 		      ptr += 32;
3069 		  }
3070 		else
3071 		  {
3072 		      /* compressing any other intermediate vertex */
3073 		      fx = (float) (x - last_x);
3074 		      fy = (float) (y - last_y);
3075 		      fz = (float) (z - last_z);
3076 		      gaiaExportF32 (ptr, fx, 1, endian_arch);
3077 		      gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3078 		      gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3079 		      gaiaExport64 (ptr + 12, m, 1, endian_arch);
3080 		      ptr += 20;
3081 		  }
3082 		last_x = x;
3083 		last_y = y;
3084 		last_z = z;
3085 	    }
3086 	  *ptr = GAIA_MARK_END;	/* END signature */
3087 	  break;
3088       case GAIA_POLYGON:
3089 	  *ptr = GAIA_MARK_START;	/* START signature */
3090 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
3091 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
3092 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
3093 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
3094 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
3095 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
3096 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
3097 	  gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGON, 1, endian_arch);	/* class POLYGON */
3098 	  gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
3099 	  rng = polyg->Exterior;
3100 	  gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch);	/* # points - exterior ring */
3101 	  ptr += 51;
3102 	  for (iv = 0; iv < rng->Points; iv++)
3103 	    {
3104 		gaiaGetPoint (rng->Coords, iv, &x, &y);
3105 		if (iv == 0 || iv == (rng->Points - 1))
3106 		  {
3107 		      /* first and last vertices are uncompressed */
3108 		      gaiaExport64 (ptr, x, 1, endian_arch);
3109 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);
3110 		      ptr += 16;
3111 		  }
3112 		else
3113 		  {
3114 		      /* compressing any other intermediate vertex */
3115 		      fx = (float) (x - last_x);
3116 		      fy = (float) (y - last_y);
3117 		      gaiaExportF32 (ptr, fx, 1, endian_arch);
3118 		      gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3119 		      ptr += 8;
3120 		  }
3121 		last_x = x;
3122 		last_y = y;
3123 	    }
3124 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
3125 	    {
3126 		rng = polyg->Interiors + ib;
3127 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
3128 		ptr += 4;
3129 		for (iv = 0; iv < rng->Points; iv++)
3130 		  {
3131 		      gaiaGetPoint (rng->Coords, iv, &x, &y);
3132 		      if (iv == 0 || iv == (rng->Points - 1))
3133 			{
3134 			    /* first and last vertices are uncompressed */
3135 			    gaiaExport64 (ptr, x, 1, endian_arch);
3136 			    gaiaExport64 (ptr + 8, y, 1, endian_arch);
3137 			    ptr += 16;
3138 			}
3139 		      else
3140 			{
3141 			    /* compressing any other intermediate vertex */
3142 			    fx = (float) (x - last_x);
3143 			    fy = (float) (y - last_y);
3144 			    gaiaExportF32 (ptr, fx, 1, endian_arch);
3145 			    gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3146 			    ptr += 8;
3147 			}
3148 		      last_x = x;
3149 		      last_y = y;
3150 		  }
3151 	    }
3152 	  *ptr = GAIA_MARK_END;	/* END signature */
3153 	  break;
3154       case GAIA_POLYGONZ:
3155 	  *ptr = GAIA_MARK_START;	/* START signature */
3156 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
3157 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
3158 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
3159 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
3160 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
3161 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
3162 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
3163 	  gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGONZ, 1, endian_arch);	/* class POLYGON XYZ */
3164 	  gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
3165 	  rng = polyg->Exterior;
3166 	  gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch);	/* # points - exterior ring */
3167 	  ptr += 51;
3168 	  for (iv = 0; iv < rng->Points; iv++)
3169 	    {
3170 		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3171 		if (iv == 0 || iv == (rng->Points - 1))
3172 		  {
3173 		      /* first and last vertices are uncompressed */
3174 		      gaiaExport64 (ptr, x, 1, endian_arch);
3175 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);
3176 		      gaiaExport64 (ptr + 16, z, 1, endian_arch);
3177 		      ptr += 24;
3178 		  }
3179 		else
3180 		  {
3181 		      /* compressing any other intermediate vertex */
3182 		      fx = (float) (x - last_x);
3183 		      fy = (float) (y - last_y);
3184 		      fz = (float) (z - last_z);
3185 		      gaiaExportF32 (ptr, fx, 1, endian_arch);
3186 		      gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3187 		      gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3188 		      ptr += 12;
3189 		  }
3190 		last_x = x;
3191 		last_y = y;
3192 		last_z = z;
3193 	    }
3194 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
3195 	    {
3196 		rng = polyg->Interiors + ib;
3197 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
3198 		ptr += 4;
3199 		for (iv = 0; iv < rng->Points; iv++)
3200 		  {
3201 		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3202 		      if (iv == 0 || iv == (rng->Points - 1))
3203 			{
3204 			    /* first and last vertices are uncompressed */
3205 			    gaiaExport64 (ptr, x, 1, endian_arch);
3206 			    gaiaExport64 (ptr + 8, y, 1, endian_arch);
3207 			    gaiaExport64 (ptr + 16, z, 1, endian_arch);
3208 			    ptr += 24;
3209 			}
3210 		      else
3211 			{
3212 			    /* compressing any other intermediate vertex */
3213 			    fx = (float) (x - last_x);
3214 			    fy = (float) (y - last_y);
3215 			    fz = (float) (z - last_z);
3216 			    gaiaExportF32 (ptr, fx, 1, endian_arch);
3217 			    gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3218 			    gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3219 			    ptr += 12;
3220 			}
3221 		      last_x = x;
3222 		      last_y = y;
3223 		      last_z = z;
3224 		  }
3225 	    }
3226 	  *ptr = GAIA_MARK_END;	/* END signature */
3227 	  break;
3228       case GAIA_POLYGONM:
3229 	  *ptr = GAIA_MARK_START;	/* START signature */
3230 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
3231 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
3232 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
3233 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
3234 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
3235 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
3236 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
3237 	  gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGONM, 1, endian_arch);	/* class POLYGON XYM */
3238 	  gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
3239 	  rng = polyg->Exterior;
3240 	  gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch);	/* # points - exterior ring */
3241 	  ptr += 51;
3242 	  for (iv = 0; iv < rng->Points; iv++)
3243 	    {
3244 		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3245 		if (iv == 0 || iv == (rng->Points - 1))
3246 		  {
3247 		      /* first and last vertices are uncompressed */
3248 		      gaiaExport64 (ptr, x, 1, endian_arch);
3249 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);
3250 		      gaiaExport64 (ptr + 16, m, 1, endian_arch);
3251 		      ptr += 24;
3252 		  }
3253 		else
3254 		  {
3255 		      /* compressing any other intermediate vertex */
3256 		      fx = (float) (x - last_x);
3257 		      fy = (float) (y - last_y);
3258 		      gaiaExportF32 (ptr, fx, 1, endian_arch);
3259 		      gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3260 		      gaiaExport64 (ptr + 8, m, 1, endian_arch);
3261 		      ptr += 16;
3262 		  }
3263 		last_x = x;
3264 		last_y = y;
3265 	    }
3266 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
3267 	    {
3268 		rng = polyg->Interiors + ib;
3269 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
3270 		ptr += 4;
3271 		for (iv = 0; iv < rng->Points; iv++)
3272 		  {
3273 		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3274 		      if (iv == 0 || iv == (rng->Points - 1))
3275 			{
3276 			    /* first and last vertices are uncompressed */
3277 			    gaiaExport64 (ptr, x, 1, endian_arch);
3278 			    gaiaExport64 (ptr + 8, y, 1, endian_arch);
3279 			    gaiaExport64 (ptr + 16, m, 1, endian_arch);
3280 			    ptr += 24;
3281 			}
3282 		      else
3283 			{
3284 			    /* compressing any other intermediate vertex */
3285 			    fx = (float) (x - last_x);
3286 			    fy = (float) (y - last_y);
3287 			    gaiaExportF32 (ptr, fx, 1, endian_arch);
3288 			    gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3289 			    gaiaExport64 (ptr + 8, m, 1, endian_arch);
3290 			    ptr += 16;
3291 			}
3292 		      last_x = x;
3293 		      last_y = y;
3294 		  }
3295 	    }
3296 	  *ptr = GAIA_MARK_END;	/* END signature */
3297 	  break;
3298       case GAIA_POLYGONZM:
3299 	  *ptr = GAIA_MARK_START;	/* START signature */
3300 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
3301 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
3302 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
3303 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
3304 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
3305 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
3306 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
3307 	  gaiaExport32 (ptr + 39, GAIA_COMPRESSED_POLYGONZM, 1, endian_arch);	/* class POLYGON */
3308 	  gaiaExport32 (ptr + 43, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
3309 	  rng = polyg->Exterior;
3310 	  gaiaExport32 (ptr + 47, rng->Points, 1, endian_arch);	/* # points - exterior ring */
3311 	  ptr += 51;
3312 	  for (iv = 0; iv < rng->Points; iv++)
3313 	    {
3314 		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3315 		if (iv == 0 || iv == (rng->Points - 1))
3316 		  {
3317 		      /* first and last vertices are uncompressed */
3318 		      gaiaExport64 (ptr, x, 1, endian_arch);
3319 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);
3320 		      gaiaExport64 (ptr + 16, z, 1, endian_arch);
3321 		      gaiaExport64 (ptr + 24, m, 1, endian_arch);
3322 		      ptr += 32;
3323 		  }
3324 		else
3325 		  {
3326 		      /* compressing any other intermediate vertex */
3327 		      fx = (float) (x - last_x);
3328 		      fy = (float) (y - last_y);
3329 		      fz = (float) (z - last_z);
3330 		      gaiaExportF32 (ptr, fx, 1, endian_arch);
3331 		      gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3332 		      gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3333 		      gaiaExport64 (ptr + 12, m, 1, endian_arch);
3334 		      ptr += 20;
3335 		  }
3336 		last_x = x;
3337 		last_y = y;
3338 		last_z = z;
3339 	    }
3340 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
3341 	    {
3342 		rng = polyg->Interiors + ib;
3343 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
3344 		ptr += 4;
3345 		for (iv = 0; iv < rng->Points; iv++)
3346 		  {
3347 		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3348 		      if (iv == 0 || iv == (rng->Points - 1))
3349 			{
3350 			    /* first and last vertices are uncompressed */
3351 			    gaiaExport64 (ptr, x, 1, endian_arch);
3352 			    gaiaExport64 (ptr + 8, y, 1, endian_arch);
3353 			    gaiaExport64 (ptr + 16, z, 1, endian_arch);
3354 			    gaiaExport64 (ptr + 24, m, 1, endian_arch);
3355 			    ptr += 32;
3356 			}
3357 		      else
3358 			{
3359 			    /* compressing any other intermediate vertex */
3360 			    fx = (float) (x - last_x);
3361 			    fy = (float) (y - last_y);
3362 			    fz = (float) (z - last_z);
3363 			    gaiaExportF32 (ptr, fx, 1, endian_arch);
3364 			    gaiaExportF32 (ptr + 4, fy, 1, endian_arch);
3365 			    gaiaExportF32 (ptr + 8, fz, 1, endian_arch);
3366 			    gaiaExport64 (ptr + 12, m, 1, endian_arch);
3367 			    ptr += 20;
3368 			}
3369 		      last_x = x;
3370 		      last_y = y;
3371 		      last_z = z;
3372 		  }
3373 	    }
3374 	  *ptr = GAIA_MARK_END;	/* END signature */
3375 	  break;
3376       default:
3377 	  /* this one is a MULTIxxxx or a GEOMETRYCOLLECTION - building the main header */
3378 	  *ptr = GAIA_MARK_START;	/* START signature */
3379 	  *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
3380 	  gaiaExport32 (ptr + 2, geom->Srid, 1, endian_arch);	/* the SRID */
3381 	  gaiaExport64 (ptr + 6, geom->MinX, 1, endian_arch);	/* MBR - minimum X */
3382 	  gaiaExport64 (ptr + 14, geom->MinY, 1, endian_arch);	/* MBR - minimum Y */
3383 	  gaiaExport64 (ptr + 22, geom->MaxX, 1, endian_arch);	/* MBR - maximum X */
3384 	  gaiaExport64 (ptr + 30, geom->MaxY, 1, endian_arch);	/* MBR - maximum Y */
3385 	  *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
3386 	  gaiaExport32 (ptr + 39, type, 1, endian_arch);	/* geometric class */
3387 	  gaiaExport32 (ptr + 43, entities, 1, endian_arch);	/* # entities */
3388 	  ptr += 47;
3389 	  point = geom->FirstPoint;
3390 	  while (point)
3391 	    {
3392 		*ptr = GAIA_MARK_ENTITY;	/* ENTITY signature */
3393 		if (geom->DimensionModel == GAIA_XY_Z)
3394 		  {
3395 		      gaiaExport32 (ptr + 1, GAIA_POINTZ, 1, endian_arch);	/* class POINT XYZ */
3396 		      gaiaExport64 (ptr + 5, point->X, 1, endian_arch);	/* X */
3397 		      gaiaExport64 (ptr + 13, point->Y, 1, endian_arch);	/* Y */
3398 		      gaiaExport64 (ptr + 21, point->Z, 1, endian_arch);	/* Z */
3399 		      ptr += 29;
3400 		  }
3401 		else if (geom->DimensionModel == GAIA_XY_M)
3402 		  {
3403 		      gaiaExport32 (ptr + 1, GAIA_POINTM, 1, endian_arch);	/* class POINT XYM */
3404 		      gaiaExport64 (ptr + 5, point->X, 1, endian_arch);	/* X */
3405 		      gaiaExport64 (ptr + 13, point->Y, 1, endian_arch);	/* Y */
3406 		      gaiaExport64 (ptr + 21, point->M, 1, endian_arch);	/* M */
3407 		      ptr += 29;
3408 		  }
3409 		else if (geom->DimensionModel == GAIA_XY_Z_M)
3410 		  {
3411 		      gaiaExport32 (ptr + 1, GAIA_POINTZM, 1, endian_arch);	/* class POINT XYZM */
3412 		      gaiaExport64 (ptr + 5, point->X, 1, endian_arch);	/* X */
3413 		      gaiaExport64 (ptr + 13, point->Y, 1, endian_arch);	/* Y */
3414 		      gaiaExport64 (ptr + 21, point->Z, 1, endian_arch);	/* Z */
3415 		      gaiaExport64 (ptr + 29, point->M, 1, endian_arch);	/* M */
3416 		      ptr += 37;
3417 		  }
3418 		else
3419 		  {
3420 		      gaiaExport32 (ptr + 1, GAIA_POINT, 1, endian_arch);	/* class POINT */
3421 		      gaiaExport64 (ptr + 5, point->X, 1, endian_arch);	/* X */
3422 		      gaiaExport64 (ptr + 13, point->Y, 1, endian_arch);	/* Y */
3423 		      ptr += 21;
3424 		  }
3425 		point = point->Next;
3426 	    }
3427 	  line = geom->FirstLinestring;
3428 	  while (line)
3429 	    {
3430 		*ptr = GAIA_MARK_ENTITY;	/* ENTITY signature */
3431 		if (geom->DimensionModel == GAIA_XY_Z)
3432 		    gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRINGZ, 1, endian_arch);	/* class LINESTRING XYZ */
3433 		else if (geom->DimensionModel == GAIA_XY_M)
3434 		    gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRINGM, 1, endian_arch);	/* class LINESTRING XYM */
3435 		else if (geom->DimensionModel == GAIA_XY_Z_M)
3436 		    gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRINGZM, 1, endian_arch);	/* class LINESTRING XYZM */
3437 		else
3438 		    gaiaExport32 (ptr + 1, GAIA_COMPRESSED_LINESTRING, 1, endian_arch);	/* class LINESTRING */
3439 		gaiaExport32 (ptr + 5, line->Points, 1, endian_arch);	/* # points */
3440 		ptr += 9;
3441 		for (iv = 0; iv < line->Points; iv++)
3442 		  {
3443 		      z = 0.0;
3444 		      m = 0.0;
3445 		      if (geom->DimensionModel == GAIA_XY_Z)
3446 			{
3447 			    gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
3448 			}
3449 		      else if (geom->DimensionModel == GAIA_XY_M)
3450 			{
3451 			    gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
3452 			}
3453 		      else if (geom->DimensionModel == GAIA_XY_Z_M)
3454 			{
3455 			    gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
3456 			}
3457 		      else
3458 			{
3459 			    gaiaGetPoint (line->Coords, iv, &x, &y);
3460 			}
3461 		      if (iv == 0 || iv == (line->Points - 1))
3462 			{
3463 			    /* first and last vertices are uncompressed */
3464 			    gaiaExport64 (ptr, x, 1, endian_arch);	/* X */
3465 			    gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y */
3466 			    ptr += 16;
3467 			}
3468 		      else
3469 			{
3470 			    /* compressing any other intermediate vertex */
3471 			    fx = (float) (x - last_x);
3472 			    fy = (float) (y - last_y);
3473 			    gaiaExportF32 (ptr, fx, 1, endian_arch);	/* X */
3474 			    gaiaExportF32 (ptr + 4, fy, 1, endian_arch);	/* Y */
3475 			    ptr += 8;
3476 			}
3477 		      if (geom->DimensionModel == GAIA_XY_Z)
3478 			{
3479 			    if (iv == 0 || iv == (line->Points - 1))
3480 			      {
3481 				  /* first and last vertices are uncompressed */
3482 				  gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
3483 				  ptr += 8;
3484 			      }
3485 			    else
3486 			      {
3487 				  /* compressing any other intermediate vertex */
3488 				  fz = (float) (z - last_z);
3489 				  gaiaExportF32 (ptr, fz, 1, endian_arch);	/* Z */
3490 				  ptr += 4;
3491 			      }
3492 			}
3493 		      if (geom->DimensionModel == GAIA_XY_M)
3494 			{
3495 			    gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
3496 			    ptr += 8;
3497 			}
3498 		      if (geom->DimensionModel == GAIA_XY_Z_M)
3499 			{
3500 			    if (iv == 0 || iv == (line->Points - 1))
3501 			      {
3502 				  /* first and last vertices are uncompressed */
3503 				  gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
3504 				  ptr += 8;
3505 			      }
3506 			    else
3507 			      {
3508 				  /* compressing any other intermediate vertex */
3509 				  fz = (float) (z - last_z);
3510 				  gaiaExportF32 (ptr, fz, 1, endian_arch);	/* Z */
3511 				  ptr += 4;
3512 			      }
3513 			    gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
3514 			    ptr += 8;
3515 			}
3516 		      last_x = x;
3517 		      last_y = y;
3518 		      last_z = z;
3519 		  }
3520 		line = line->Next;
3521 	    }
3522 	  polyg = geom->FirstPolygon;
3523 	  while (polyg)
3524 	    {
3525 		*ptr = GAIA_MARK_ENTITY;	/* ENTITY signature */
3526 		if (geom->DimensionModel == GAIA_XY_Z)
3527 		    gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGONZ, 1, endian_arch);	/* class POLYGON XYZ */
3528 		else if (geom->DimensionModel == GAIA_XY_M)
3529 		    gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGONM, 1, endian_arch);	/* class POLYGON XYM */
3530 		else if (geom->DimensionModel == GAIA_XY_Z_M)
3531 		    gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGONZM, 1, endian_arch);	/* class POLYGON XYZM */
3532 		else
3533 		    gaiaExport32 (ptr + 1, GAIA_COMPRESSED_POLYGON, 1, endian_arch);	/* class POLYGON */
3534 		gaiaExport32 (ptr + 5, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
3535 		rng = polyg->Exterior;
3536 		gaiaExport32 (ptr + 9, rng->Points, 1, endian_arch);	/* # points - exterior ring */
3537 		ptr += 13;
3538 		for (iv = 0; iv < rng->Points; iv++)
3539 		  {
3540 		      z = 0.0;
3541 		      m = 0.0;
3542 		      if (geom->DimensionModel == GAIA_XY_Z)
3543 			{
3544 			    gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3545 			}
3546 		      else if (geom->DimensionModel == GAIA_XY_M)
3547 			{
3548 			    gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3549 			}
3550 		      else if (geom->DimensionModel == GAIA_XY_Z_M)
3551 			{
3552 			    gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3553 			}
3554 		      else
3555 			{
3556 			    gaiaGetPoint (rng->Coords, iv, &x, &y);
3557 			}
3558 		      if (iv == 0 || iv == (rng->Points - 1))
3559 			{
3560 			    /* first and last vertices are uncompressed */
3561 			    gaiaExport64 (ptr, x, 1, endian_arch);	/* X - exterior ring */
3562 			    gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - exterior ring */
3563 			    ptr += 16;
3564 			}
3565 		      else
3566 			{
3567 			    /* compressing any other intermediate vertex */
3568 			    fx = (float) (x - last_x);
3569 			    fy = (float) (y - last_y);
3570 			    gaiaExportF32 (ptr, fx, 1, endian_arch);	/* X */
3571 			    gaiaExportF32 (ptr + 4, fy, 1, endian_arch);	/* Y */
3572 			    ptr += 8;
3573 			}
3574 		      if (geom->DimensionModel == GAIA_XY_Z)
3575 			{
3576 			    if (iv == 0 || iv == (rng->Points - 1))
3577 			      {
3578 				  /* first and last vertices are uncompressed */
3579 				  gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
3580 				  ptr += 8;
3581 			      }
3582 			    else
3583 			      {
3584 				  /* compressing any other intermediate vertex */
3585 				  fz = (float) (z - last_z);
3586 				  gaiaExportF32 (ptr, fz, 1, endian_arch);	/* Z */
3587 				  ptr += 4;
3588 			      }
3589 			}
3590 		      if (geom->DimensionModel == GAIA_XY_M)
3591 			{
3592 			    gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
3593 			    ptr += 8;
3594 			}
3595 		      if (geom->DimensionModel == GAIA_XY_Z_M)
3596 			{
3597 			    if (iv == 0 || iv == (rng->Points - 1))
3598 			      {
3599 				  /* first and last vertices are uncompressed */
3600 				  gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
3601 				  ptr += 8;
3602 			      }
3603 			    else
3604 			      {
3605 				  /* compressing any other intermediate vertex */
3606 				  fz = (float) (z - last_z);
3607 				  gaiaExportF32 (ptr, fz, 1, endian_arch);	/* Z */
3608 				  ptr += 4;
3609 			      }
3610 			    gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
3611 			    ptr += 8;
3612 			}
3613 		      last_x = x;
3614 		      last_y = y;
3615 		      last_z = z;
3616 		  }
3617 		for (ib = 0; ib < polyg->NumInteriors; ib++)
3618 		  {
3619 		      rng = polyg->Interiors + ib;
3620 		      gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
3621 		      ptr += 4;
3622 		      for (iv = 0; iv < rng->Points; iv++)
3623 			{
3624 			    z = 0.0;
3625 			    m = 0.0;
3626 			    if (geom->DimensionModel == GAIA_XY_Z)
3627 			      {
3628 				  gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3629 			      }
3630 			    else if (geom->DimensionModel == GAIA_XY_M)
3631 			      {
3632 				  gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3633 			      }
3634 			    else if (geom->DimensionModel == GAIA_XY_Z_M)
3635 			      {
3636 				  gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z,
3637 						    &m);
3638 			      }
3639 			    else
3640 			      {
3641 				  gaiaGetPoint (rng->Coords, iv, &x, &y);
3642 			      }
3643 			    if (iv == 0 || iv == (rng->Points - 1))
3644 			      {
3645 				  /* first and last vertices are uncompressed */
3646 				  gaiaExport64 (ptr, x, 1, endian_arch);	/* X - interior ring */
3647 				  gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - interior ring */
3648 				  ptr += 16;
3649 			      }
3650 			    else
3651 			      {
3652 				  /* compressing any other intermediate vertex */
3653 				  fx = (float) (x - last_x);
3654 				  fy = (float) (y - last_y);
3655 				  gaiaExportF32 (ptr, fx, 1, endian_arch);	/* X */
3656 				  gaiaExportF32 (ptr + 4, fy, 1, endian_arch);	/* Y */
3657 				  ptr += 8;
3658 			      }
3659 			    if (geom->DimensionModel == GAIA_XY_Z)
3660 			      {
3661 				  if (iv == 0 || iv == (rng->Points - 1))
3662 				    {
3663 					/* first and last vertices are uncompressed */
3664 					gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
3665 					ptr += 8;
3666 				    }
3667 				  else
3668 				    {
3669 					/* compressing any other intermediate vertex */
3670 					fz = (float) (z - last_z);
3671 					gaiaExportF32 (ptr, fz, 1, endian_arch);	/* Z */
3672 					ptr += 4;
3673 				    }
3674 			      }
3675 			    if (geom->DimensionModel == GAIA_XY_M)
3676 			      {
3677 				  gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
3678 				  ptr += 8;
3679 			      }
3680 			    if (geom->DimensionModel == GAIA_XY_Z_M)
3681 			      {
3682 				  if (iv == 0 || iv == (rng->Points - 1))
3683 				    {
3684 					/* first and last vertices are uncompressed */
3685 					gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
3686 					ptr += 8;
3687 				    }
3688 				  else
3689 				    {
3690 					/* compressing any other intermediate vertex */
3691 					fz = (float) (z - last_z);
3692 					gaiaExportF32 (ptr, fz, 1, endian_arch);	/* Z */
3693 					ptr += 4;
3694 				    }
3695 				  gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
3696 				  ptr += 8;
3697 			      }
3698 			    last_x = x;
3699 			    last_y = y;
3700 			    last_z = z;
3701 			}
3702 		  }
3703 		polyg = polyg->Next;
3704 	    }
3705 	  *ptr = GAIA_MARK_END;	/* END signature */
3706       };
3707 }
3708 
3709 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromWkb(const unsigned char * blob,unsigned int size)3710 gaiaFromWkb (const unsigned char *blob, unsigned int size)
3711 {
3712 /* decoding from WKB to GEOMETRY  */
3713     int type;
3714     int little_endian;
3715     gaiaGeomCollPtr geo = NULL;
3716     int endian_arch = gaiaEndianArch ();
3717     if (size < 5)
3718 	return NULL;
3719     if (*(blob + 0) == 0x01)
3720 	little_endian = GAIA_LITTLE_ENDIAN;
3721     else
3722 	little_endian = GAIA_BIG_ENDIAN;
3723     type = gaiaImport32 (blob + 1, little_endian, endian_arch);
3724     if (type == GAIA_POINTZ || type == GAIA_LINESTRINGZ || type == GAIA_POLYGONZ
3725 	|| type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
3726 	|| type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
3727 	|| type == GAIA_GEOSWKB_POINTZ || type == GAIA_GEOSWKB_LINESTRINGZ
3728 	|| type == GAIA_GEOSWKB_POLYGONZ || type == GAIA_GEOSWKB_MULTIPOINTZ
3729 	|| type == GAIA_GEOSWKB_MULTILINESTRINGZ
3730 	|| type == GAIA_GEOSWKB_MULTIPOLYGONZ
3731 	|| type == GAIA_GEOSWKB_GEOMETRYCOLLECTIONZ)
3732 	geo = gaiaAllocGeomCollXYZ ();
3733     else if (type == GAIA_POINTM || type == GAIA_LINESTRINGM
3734 	     || type == GAIA_POLYGONM || type == GAIA_MULTIPOINTM
3735 	     || type == GAIA_MULTILINESTRINGM || type == GAIA_MULTIPOLYGONM
3736 	     || type == GAIA_GEOMETRYCOLLECTIONM)
3737 	geo = gaiaAllocGeomCollXYM ();
3738     else if (type == GAIA_POINTZM || type == GAIA_LINESTRINGZM
3739 	     || type == GAIA_POLYGONZM || type == GAIA_MULTIPOINTZM
3740 	     || type == GAIA_MULTILINESTRINGZM || type == GAIA_MULTIPOLYGONZM
3741 	     || type == GAIA_GEOMETRYCOLLECTIONZM)
3742 	geo = gaiaAllocGeomCollXYZM ();
3743     else
3744 	geo = gaiaAllocGeomColl ();
3745     geo->Srid = 0;
3746     geo->endian_arch = (char) endian_arch;
3747     geo->endian = (char) little_endian;
3748     geo->blob = blob;
3749     geo->size = size;
3750     geo->offset = 5;
3751     switch (type)
3752       {
3753       case GAIA_POINT:
3754 	  ParseWkbPoint (geo);
3755 	  break;
3756       case GAIA_POINTZ:
3757       case GAIA_GEOSWKB_POINTZ:
3758 	  ParseWkbPointZ (geo);
3759 	  break;
3760       case GAIA_POINTM:
3761 	  ParseWkbPointM (geo);
3762 	  break;
3763       case GAIA_POINTZM:
3764 	  ParseWkbPointZM (geo);
3765 	  break;
3766       case GAIA_LINESTRING:
3767 	  ParseWkbLine (geo);
3768 	  break;
3769       case GAIA_LINESTRINGZ:
3770       case GAIA_GEOSWKB_LINESTRINGZ:
3771 	  ParseWkbLineZ (geo);
3772 	  break;
3773       case GAIA_LINESTRINGM:
3774 	  ParseWkbLineM (geo);
3775 	  break;
3776       case GAIA_LINESTRINGZM:
3777 	  ParseWkbLineZM (geo);
3778 	  break;
3779       case GAIA_POLYGON:
3780 	  ParseWkbPolygon (geo);
3781 	  break;
3782       case GAIA_POLYGONZ:
3783       case GAIA_GEOSWKB_POLYGONZ:
3784 	  ParseWkbPolygonZ (geo);
3785 	  break;
3786       case GAIA_POLYGONM:
3787 	  ParseWkbPolygonM (geo);
3788 	  break;
3789       case GAIA_POLYGONZM:
3790 	  ParseWkbPolygonZM (geo);
3791 	  break;
3792       case GAIA_MULTIPOINT:
3793       case GAIA_MULTILINESTRING:
3794       case GAIA_MULTIPOLYGON:
3795       case GAIA_GEOMETRYCOLLECTION:
3796       case GAIA_MULTIPOINTZ:
3797       case GAIA_MULTILINESTRINGZ:
3798       case GAIA_MULTIPOLYGONZ:
3799       case GAIA_GEOMETRYCOLLECTIONZ:
3800       case GAIA_GEOSWKB_MULTIPOINTZ:
3801       case GAIA_GEOSWKB_MULTILINESTRINGZ:
3802       case GAIA_GEOSWKB_MULTIPOLYGONZ:
3803       case GAIA_GEOSWKB_GEOMETRYCOLLECTIONZ:
3804       case GAIA_MULTIPOINTM:
3805       case GAIA_MULTILINESTRINGM:
3806       case GAIA_MULTIPOLYGONM:
3807       case GAIA_GEOMETRYCOLLECTIONM:
3808       case GAIA_MULTIPOINTZM:
3809       case GAIA_MULTILINESTRINGZM:
3810       case GAIA_MULTIPOLYGONZM:
3811       case GAIA_GEOMETRYCOLLECTIONZM:
3812 	  ParseWkbGeometry (geo, 1);
3813 	  break;
3814       default:
3815 	  break;
3816       };
3817     gaiaMbrGeometry (geo);
3818     switch (type)
3819       {
3820       case GAIA_POINT:
3821       case GAIA_POINTZ:
3822       case GAIA_GEOSWKB_POINTZ:
3823       case GAIA_POINTM:
3824       case GAIA_POINTZM:
3825 	  geo->DeclaredType = GAIA_POINT;
3826 	  break;
3827       case GAIA_LINESTRING:
3828       case GAIA_LINESTRINGZ:
3829       case GAIA_GEOSWKB_LINESTRINGZ:
3830       case GAIA_LINESTRINGM:
3831       case GAIA_LINESTRINGZM:
3832 	  geo->DeclaredType = GAIA_LINESTRING;
3833 	  break;
3834       case GAIA_POLYGON:
3835       case GAIA_POLYGONZ:
3836       case GAIA_GEOSWKB_POLYGONZ:
3837       case GAIA_POLYGONM:
3838       case GAIA_POLYGONZM:
3839 	  geo->DeclaredType = GAIA_POLYGON;
3840 	  break;
3841       case GAIA_MULTIPOINT:
3842       case GAIA_MULTIPOINTZ:
3843       case GAIA_GEOSWKB_MULTIPOINTZ:
3844       case GAIA_MULTIPOINTM:
3845       case GAIA_MULTIPOINTZM:
3846 	  geo->DeclaredType = GAIA_MULTIPOINT;
3847 	  break;
3848       case GAIA_MULTILINESTRING:
3849       case GAIA_MULTILINESTRINGZ:
3850       case GAIA_GEOSWKB_MULTILINESTRINGZ:
3851       case GAIA_MULTILINESTRINGM:
3852       case GAIA_MULTILINESTRINGZM:
3853 	  geo->DeclaredType = GAIA_MULTILINESTRING;
3854 	  break;
3855       case GAIA_MULTIPOLYGON:
3856       case GAIA_MULTIPOLYGONZ:
3857       case GAIA_GEOSWKB_MULTIPOLYGONZ:
3858       case GAIA_MULTIPOLYGONM:
3859       case GAIA_MULTIPOLYGONZM:
3860 	  geo->DeclaredType = GAIA_MULTIPOLYGON;
3861 	  break;
3862       case GAIA_GEOMETRYCOLLECTION:
3863       case GAIA_GEOMETRYCOLLECTIONZ:
3864       case GAIA_GEOSWKB_GEOMETRYCOLLECTIONZ:
3865       case GAIA_GEOMETRYCOLLECTIONM:
3866       case GAIA_GEOMETRYCOLLECTIONZM:
3867 	  geo->DeclaredType = GAIA_GEOMETRYCOLLECTION;
3868 	  break;
3869       }
3870     return geo;
3871 }
3872 
3873 GAIAGEO_DECLARE char *
gaiaToHexWkb(gaiaGeomCollPtr geom)3874 gaiaToHexWkb (gaiaGeomCollPtr geom)
3875 {
3876 /* builds the hexadecimal WKB representation for this GEOMETRY */
3877     unsigned char *wkb = NULL;
3878     int size = 0;
3879     char *hexbuf = NULL;
3880     int i;
3881     char hex[16];
3882     char *p;
3883     gaiaToWkb (geom, &wkb, &size);
3884     if (!wkb)
3885 	return NULL;
3886     hexbuf = malloc ((size * 2) + 1);
3887     p = hexbuf;
3888     for (i = 0; i < size; i++)
3889       {
3890 	  sprintf (hex, "%02X", *(wkb + i));
3891 	  *p++ = hex[0];
3892 	  *p++ = hex[1];
3893       }
3894     *p = '\0';
3895     return hexbuf;
3896 }
3897 
3898 GAIAGEO_DECLARE void
gaiaToWkb(gaiaGeomCollPtr geom,unsigned char ** result,int * size)3899 gaiaToWkb (gaiaGeomCollPtr geom, unsigned char **result, int *size)
3900 {
3901 /* builds the WKB representation for this GEOMETRY */
3902     int ib;
3903     int iv;
3904     double x;
3905     double y;
3906     double z = 0.0;
3907     double m = 0.0;
3908     int entities = 0;
3909     int n_points = 0;
3910     int n_linestrings = 0;
3911     int n_polygons = 0;
3912     int type;
3913     unsigned char *ptr;
3914     gaiaPointPtr pt;
3915     gaiaLinestringPtr ln;
3916     gaiaPolygonPtr pg;
3917     gaiaRingPtr rng;
3918     gaiaPointPtr point = NULL;
3919     gaiaLinestringPtr line = NULL;
3920     gaiaPolygonPtr polyg = NULL;
3921     int endian_arch = gaiaEndianArch ();
3922     gaiaMbrGeometry (geom);
3923 /* how many entities, and of what kind, do we have ? */
3924     pt = geom->FirstPoint;
3925     while (pt)
3926       {
3927 	  point = pt;
3928 	  entities++;
3929 	  n_points++;
3930 	  pt = pt->Next;
3931       }
3932     ln = geom->FirstLinestring;
3933     while (ln)
3934       {
3935 	  line = ln;
3936 	  entities++;
3937 	  n_linestrings++;
3938 	  ln = ln->Next;
3939       }
3940     pg = geom->FirstPolygon;
3941     while (pg)
3942       {
3943 	  polyg = pg;
3944 	  entities++;
3945 	  n_polygons++;
3946 	  pg = pg->Next;
3947       }
3948     *size = 0;
3949     *result = NULL;
3950     if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
3951 	return;
3952 /* ok, we can determine the geometry class */
3953     if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
3954       {
3955 	  if (geom->DeclaredType == GAIA_MULTIPOINT)
3956 	    {
3957 		if (geom->DimensionModel == GAIA_XY_Z)
3958 		    type = GAIA_MULTIPOINTZ;
3959 		else if (geom->DimensionModel == GAIA_XY_M)
3960 		    type = GAIA_MULTIPOINTM;
3961 		else if (geom->DimensionModel == GAIA_XY_Z_M)
3962 		    type = GAIA_MULTIPOINTZM;
3963 		else
3964 		    type = GAIA_MULTIPOINT;
3965 	    }
3966 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3967 	    {
3968 		if (geom->DimensionModel == GAIA_XY_Z)
3969 		    type = GAIA_GEOMETRYCOLLECTIONZ;
3970 		else if (geom->DimensionModel == GAIA_XY_M)
3971 		    type = GAIA_GEOMETRYCOLLECTIONM;
3972 		else if (geom->DimensionModel == GAIA_XY_Z_M)
3973 		    type = GAIA_GEOMETRYCOLLECTIONZM;
3974 		else
3975 		    type = GAIA_GEOMETRYCOLLECTION;
3976 	    }
3977 	  else
3978 	    {
3979 		if (geom->DimensionModel == GAIA_XY_Z)
3980 		    type = GAIA_POINTZ;
3981 		else if (geom->DimensionModel == GAIA_XY_M)
3982 		    type = GAIA_POINTM;
3983 		else if (geom->DimensionModel == GAIA_XY_Z_M)
3984 		    type = GAIA_POINTZM;
3985 		else
3986 		    type = GAIA_POINT;
3987 	    }
3988       }
3989     else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
3990       {
3991 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3992 	    {
3993 		if (geom->DimensionModel == GAIA_XY_Z)
3994 		    type = GAIA_GEOMETRYCOLLECTIONZ;
3995 		else if (geom->DimensionModel == GAIA_XY_M)
3996 		    type = GAIA_GEOMETRYCOLLECTIONM;
3997 		else if (geom->DimensionModel == GAIA_XY_Z_M)
3998 		    type = GAIA_GEOMETRYCOLLECTIONZM;
3999 		else
4000 		    type = GAIA_GEOMETRYCOLLECTION;
4001 	    }
4002 	  else
4003 	    {
4004 		if (geom->DimensionModel == GAIA_XY_Z)
4005 		    type = GAIA_MULTIPOINTZ;
4006 		else if (geom->DimensionModel == GAIA_XY_M)
4007 		    type = GAIA_MULTIPOINTM;
4008 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4009 		    type = GAIA_MULTIPOINTZM;
4010 		else
4011 		    type = GAIA_MULTIPOINT;
4012 	    }
4013       }
4014     else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
4015       {
4016 	  if (geom->DeclaredType == GAIA_MULTILINESTRING)
4017 	    {
4018 		if (geom->DimensionModel == GAIA_XY_Z)
4019 		    type = GAIA_MULTILINESTRINGZ;
4020 		else if (geom->DimensionModel == GAIA_XY_M)
4021 		    type = GAIA_MULTILINESTRINGM;
4022 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4023 		    type = GAIA_MULTILINESTRINGZM;
4024 		else
4025 		    type = GAIA_MULTILINESTRING;
4026 	    }
4027 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
4028 	    {
4029 		if (geom->DimensionModel == GAIA_XY_Z)
4030 		    type = GAIA_GEOMETRYCOLLECTIONZ;
4031 		else if (geom->DimensionModel == GAIA_XY_M)
4032 		    type = GAIA_GEOMETRYCOLLECTIONM;
4033 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4034 		    type = GAIA_GEOMETRYCOLLECTIONZM;
4035 		else
4036 		    type = GAIA_GEOMETRYCOLLECTION;
4037 	    }
4038 	  else
4039 	    {
4040 		if (geom->DimensionModel == GAIA_XY_Z)
4041 		    type = GAIA_LINESTRINGZ;
4042 		else if (geom->DimensionModel == GAIA_XY_M)
4043 		    type = GAIA_LINESTRINGM;
4044 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4045 		    type = GAIA_LINESTRINGZM;
4046 		else
4047 		    type = GAIA_LINESTRING;
4048 	    }
4049       }
4050     else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
4051       {
4052 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
4053 	    {
4054 		if (geom->DimensionModel == GAIA_XY_Z)
4055 		    type = GAIA_GEOMETRYCOLLECTIONZ;
4056 		else if (geom->DimensionModel == GAIA_XY_M)
4057 		    type = GAIA_GEOMETRYCOLLECTIONM;
4058 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4059 		    type = GAIA_GEOMETRYCOLLECTIONZM;
4060 		else
4061 		    type = GAIA_GEOMETRYCOLLECTION;
4062 	    }
4063 	  else
4064 	    {
4065 		if (geom->DimensionModel == GAIA_XY_Z)
4066 		    type = GAIA_MULTILINESTRINGZ;
4067 		else if (geom->DimensionModel == GAIA_XY_M)
4068 		    type = GAIA_MULTILINESTRINGM;
4069 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4070 		    type = GAIA_MULTILINESTRINGZM;
4071 		else
4072 		    type = GAIA_MULTILINESTRING;
4073 	    }
4074       }
4075     else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
4076       {
4077 	  if (geom->DeclaredType == GAIA_MULTIPOLYGON)
4078 	    {
4079 		if (geom->DimensionModel == GAIA_XY_Z)
4080 		    type = GAIA_MULTIPOLYGONZ;
4081 		else if (geom->DimensionModel == GAIA_XY_M)
4082 		    type = GAIA_MULTIPOLYGONM;
4083 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4084 		    type = GAIA_MULTIPOLYGONZM;
4085 		else
4086 		    type = GAIA_MULTIPOLYGON;
4087 	    }
4088 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
4089 	    {
4090 		if (geom->DimensionModel == GAIA_XY_Z)
4091 		    type = GAIA_GEOMETRYCOLLECTIONZ;
4092 		else if (geom->DimensionModel == GAIA_XY_M)
4093 		    type = GAIA_GEOMETRYCOLLECTIONM;
4094 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4095 		    type = GAIA_GEOMETRYCOLLECTIONZM;
4096 		else
4097 		    type = GAIA_GEOMETRYCOLLECTION;
4098 	    }
4099 	  else
4100 	    {
4101 		if (geom->DimensionModel == GAIA_XY_Z)
4102 		    type = GAIA_POLYGONZ;
4103 		else if (geom->DimensionModel == GAIA_XY_M)
4104 		    type = GAIA_POLYGONM;
4105 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4106 		    type = GAIA_POLYGONZM;
4107 		else
4108 		    type = GAIA_POLYGON;
4109 	    }
4110       }
4111     else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
4112       {
4113 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
4114 	    {
4115 		if (geom->DimensionModel == GAIA_XY_Z)
4116 		    type = GAIA_GEOMETRYCOLLECTIONZ;
4117 		else if (geom->DimensionModel == GAIA_XY_M)
4118 		    type = GAIA_GEOMETRYCOLLECTIONM;
4119 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4120 		    type = GAIA_GEOMETRYCOLLECTIONZM;
4121 		else
4122 		    type = GAIA_GEOMETRYCOLLECTION;
4123 	    }
4124 	  else
4125 	    {
4126 		if (geom->DimensionModel == GAIA_XY_Z)
4127 		    type = GAIA_MULTIPOLYGONZ;
4128 		else if (geom->DimensionModel == GAIA_XY_M)
4129 		    type = GAIA_MULTIPOLYGONM;
4130 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4131 		    type = GAIA_MULTIPOLYGONZM;
4132 		else
4133 		    type = GAIA_MULTIPOLYGON;
4134 	    }
4135       }
4136     else
4137       {
4138 	  if (geom->DimensionModel == GAIA_XY_Z)
4139 	      type = GAIA_GEOMETRYCOLLECTIONZ;
4140 	  else if (geom->DimensionModel == GAIA_XY_M)
4141 	      type = GAIA_GEOMETRYCOLLECTIONM;
4142 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
4143 	      type = GAIA_GEOMETRYCOLLECTIONZM;
4144 	  else
4145 	      type = GAIA_GEOMETRYCOLLECTION;
4146       }
4147 /* and now we compute the size of WKB */
4148     *size = 5;			/* header size */
4149     if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4150 	|| type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4151 	|| type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4152 	|| type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4153 	|| type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4154 	|| type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4155 	|| type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4156 	|| type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM)
4157 	*size += 4;
4158     point = geom->FirstPoint;
4159     while (point)
4160       {
4161 	  if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4162 	      || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4163 	      || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4164 	      || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4165 	      || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4166 	      || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4167 	      || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4168 	      || type == GAIA_MULTIPOLYGONZM
4169 	      || type == GAIA_GEOMETRYCOLLECTIONZM)
4170 	      *size += 5;
4171 	  if (geom->DimensionModel == GAIA_XY_Z
4172 	      || geom->DimensionModel == GAIA_XY_M)
4173 	      *size += (sizeof (double) * 3);	/* three doubles for each POINT */
4174 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
4175 	      *size += (sizeof (double) * 4);	/* four doubles for each POINT */
4176 	  else
4177 	      *size += (sizeof (double) * 2);	/* two doubles for each POINT */
4178 	  point = point->Next;
4179       }
4180     line = geom->FirstLinestring;
4181     while (line)
4182       {
4183 	  if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4184 	      || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4185 	      || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4186 	      || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4187 	      || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4188 	      || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4189 	      || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4190 	      || type == GAIA_MULTIPOLYGONZM
4191 	      || type == GAIA_GEOMETRYCOLLECTIONZM)
4192 	      *size += 5;
4193 	  if (geom->DimensionModel == GAIA_XY_Z
4194 	      || geom->DimensionModel == GAIA_XY_M)
4195 	      *size += (4 + ((sizeof (double) * 3) * line->Points));	/* # points + [x,y,z] for each vertex */
4196 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
4197 	      *size += (4 + ((sizeof (double) * 4) * line->Points));	/* # points + [x,y,z,m] for each vertex */
4198 	  else
4199 	      *size += (4 + ((sizeof (double) * 2) * line->Points));	/* # points + [x,y] for each vertex */
4200 	  line = line->Next;
4201       }
4202     polyg = geom->FirstPolygon;
4203     while (polyg)
4204       {
4205 	  if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4206 	      || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4207 	      || type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4208 	      || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4209 	      || type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4210 	      || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4211 	      || type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4212 	      || type == GAIA_MULTIPOLYGONZM
4213 	      || type == GAIA_GEOMETRYCOLLECTIONZM)
4214 	      *size += 5;
4215 	  rng = polyg->Exterior;
4216 	  if (geom->DimensionModel == GAIA_XY_Z
4217 	      || geom->DimensionModel == GAIA_XY_M)
4218 	      *size += (8 + ((sizeof (double) * 3) * rng->Points));	/* # rings + # points + [x,y,z] array - exterior ring */
4219 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
4220 	      *size += (8 + ((sizeof (double) * 4) * rng->Points));	/* # rings + # points + [x,y,z,m] array - exterior ring */
4221 	  else
4222 	      *size += (8 + ((sizeof (double) * 2) * rng->Points));	/* # rings + # points + [x,y] array - exterior ring */
4223 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
4224 	    {
4225 		rng = polyg->Interiors + ib;
4226 		if (geom->DimensionModel == GAIA_XY_Z
4227 		    || geom->DimensionModel == GAIA_XY_M)
4228 		    *size += (4 + ((sizeof (double) * 3) * rng->Points));	/* # points + [x,y,z] array - interior ring */
4229 		else if (geom->DimensionModel == GAIA_XY_Z_M)
4230 		    *size += (4 + ((sizeof (double) * 4) * rng->Points));	/* # points + [x,y,z,m] array - interior ring */
4231 		else
4232 		    *size += (4 + ((sizeof (double) * 2) * rng->Points));	/* # points + [x,y] array - interior ring */
4233 	    }
4234 	  polyg = polyg->Next;
4235       }
4236     *result = malloc (*size);
4237     ptr = *result;
4238 /* and finally we build the WKB */
4239     *ptr = 0x01;		/* little endian byte order */
4240     gaiaExport32 (ptr + 1, type, 1, endian_arch);	/* the main CLASS TYPE */
4241     ptr += 5;
4242     if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
4243 	|| type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4244 	|| type == GAIA_MULTIPOINTZ || type == GAIA_MULTILINESTRINGZ
4245 	|| type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4246 	|| type == GAIA_MULTIPOINTM || type == GAIA_MULTILINESTRINGM
4247 	|| type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4248 	|| type == GAIA_MULTIPOINTZM || type == GAIA_MULTILINESTRINGZM
4249 	|| type == GAIA_MULTIPOLYGONZM || type == GAIA_GEOMETRYCOLLECTIONZM)
4250       {
4251 	  gaiaExport32 (ptr, entities, 1, endian_arch);	/* it's a collection; # entities */
4252 	  ptr += 4;
4253       }
4254     point = geom->FirstPoint;
4255     while (point)
4256       {
4257 	  if (type == GAIA_MULTIPOINT || type == GAIA_GEOMETRYCOLLECTION
4258 	      || type == GAIA_MULTIPOINTZ || type == GAIA_GEOMETRYCOLLECTIONZ
4259 	      || type == GAIA_MULTIPOINTM || type == GAIA_GEOMETRYCOLLECTIONM
4260 	      || type == GAIA_MULTIPOINTZM || type == GAIA_GEOMETRYCOLLECTIONZM)
4261 	    {
4262 		*ptr = 0x01;
4263 		/* it's a collection: the CLASS TYPE for this element */
4264 		if (type == GAIA_MULTIPOINTZ
4265 		    || type == GAIA_GEOMETRYCOLLECTIONZ)
4266 		    gaiaExport32 (ptr + 1, GAIA_POINTZ, 1, endian_arch);
4267 		else if (type == GAIA_MULTIPOINTM
4268 			 || type == GAIA_GEOMETRYCOLLECTIONM)
4269 		    gaiaExport32 (ptr + 1, GAIA_POINTM, 1, endian_arch);
4270 		else if (type == GAIA_MULTIPOINTZM
4271 			 || type == GAIA_GEOMETRYCOLLECTIONZM)
4272 		    gaiaExport32 (ptr + 1, GAIA_POINTZM, 1, endian_arch);
4273 		else
4274 		    gaiaExport32 (ptr + 1, GAIA_POINT, 1, endian_arch);
4275 		ptr += 5;
4276 	    }
4277 	  gaiaExport64 (ptr, point->X, 1, endian_arch);	/* X */
4278 	  gaiaExport64 (ptr + 8, point->Y, 1, endian_arch);	/* Y */
4279 	  ptr += 16;
4280 	  if (type == GAIA_POINTZ || type == GAIA_MULTIPOINTZ
4281 	      || type == GAIA_GEOMETRYCOLLECTIONZ)
4282 	    {
4283 		gaiaExport64 (ptr, point->Z, 1, endian_arch);	/* Z */
4284 		ptr += 8;
4285 	    }
4286 	  if (type == GAIA_POINTM || type == GAIA_MULTIPOINTM
4287 	      || type == GAIA_GEOMETRYCOLLECTIONM)
4288 	    {
4289 		gaiaExport64 (ptr, point->M, 1, endian_arch);	/* M */
4290 		ptr += 8;
4291 	    }
4292 	  if (type == GAIA_POINTZM || type == GAIA_MULTIPOINTZM
4293 	      || type == GAIA_GEOMETRYCOLLECTIONZM)
4294 	    {
4295 		gaiaExport64 (ptr, point->Z, 1, endian_arch);	/* Z */
4296 		gaiaExport64 (ptr + 8, point->M, 1, endian_arch);	/* M */
4297 		ptr += 16;
4298 	    }
4299 	  point = point->Next;
4300       }
4301     line = geom->FirstLinestring;
4302     while (line)
4303       {
4304 	  if (type == GAIA_MULTILINESTRING || type == GAIA_GEOMETRYCOLLECTION
4305 	      || type == GAIA_MULTILINESTRINGZ
4306 	      || type == GAIA_GEOMETRYCOLLECTIONZ
4307 	      || type == GAIA_MULTILINESTRINGM
4308 	      || type == GAIA_GEOMETRYCOLLECTIONM
4309 	      || type == GAIA_MULTILINESTRINGZM
4310 	      || type == GAIA_GEOMETRYCOLLECTIONZM)
4311 	    {
4312 		*ptr = 0x01;
4313 		/* it's a collection: the CLASS TYPE for this element */
4314 		if (type == GAIA_MULTILINESTRINGZ
4315 		    || type == GAIA_GEOMETRYCOLLECTIONZ)
4316 		    gaiaExport32 (ptr + 1, GAIA_LINESTRINGZ, 1, endian_arch);
4317 		else if (type == GAIA_MULTILINESTRINGM
4318 			 || type == GAIA_GEOMETRYCOLLECTIONM)
4319 		    gaiaExport32 (ptr + 1, GAIA_LINESTRINGM, 1, endian_arch);
4320 		else if (type == GAIA_MULTILINESTRINGZM
4321 			 || type == GAIA_GEOMETRYCOLLECTIONZM)
4322 		    gaiaExport32 (ptr + 1, GAIA_LINESTRINGZM, 1, endian_arch);
4323 		else
4324 		    gaiaExport32 (ptr + 1, GAIA_LINESTRING, 1, endian_arch);
4325 		ptr += 5;
4326 	    }
4327 	  gaiaExport32 (ptr, line->Points, 1, endian_arch);	/* # points */
4328 	  ptr += 4;
4329 	  for (iv = 0; iv < line->Points; iv++)
4330 	    {
4331 		if (type == GAIA_LINESTRINGZ || type == GAIA_MULTILINESTRINGZ
4332 		    || type == GAIA_GEOMETRYCOLLECTIONZ)
4333 		  {
4334 		      gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
4335 		  }
4336 		else if (type == GAIA_LINESTRINGM
4337 			 || type == GAIA_MULTILINESTRINGM
4338 			 || type == GAIA_GEOMETRYCOLLECTIONM)
4339 		  {
4340 		      gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
4341 		  }
4342 		else if (type == GAIA_LINESTRINGZM
4343 			 || type == GAIA_MULTILINESTRINGZM
4344 			 || type == GAIA_GEOMETRYCOLLECTIONZM)
4345 		  {
4346 		      gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
4347 		  }
4348 		else
4349 		  {
4350 		      gaiaGetPoint (line->Coords, iv, &x, &y);
4351 		  }
4352 		gaiaExport64 (ptr, x, 1, endian_arch);	/* X */
4353 		gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y */
4354 		ptr += 16;
4355 		if (type == GAIA_LINESTRINGZ || type == GAIA_MULTILINESTRINGZ
4356 		    || type == GAIA_GEOMETRYCOLLECTIONZ)
4357 		  {
4358 		      gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
4359 		      ptr += 8;
4360 		  }
4361 		if (type == GAIA_LINESTRINGM || type == GAIA_MULTILINESTRINGM
4362 		    || type == GAIA_GEOMETRYCOLLECTIONM)
4363 		  {
4364 		      gaiaExport64 (ptr, m, 1, endian_arch);	/* M */
4365 		      ptr += 8;
4366 		  }
4367 		if (type == GAIA_LINESTRINGZM || type == GAIA_MULTILINESTRINGZM
4368 		    || type == GAIA_GEOMETRYCOLLECTIONZM)
4369 		  {
4370 		      gaiaExport64 (ptr, z, 1, endian_arch);	/* Z */
4371 		      gaiaExport64 (ptr + 8, m, 1, endian_arch);	/* M */
4372 		      ptr += 16;
4373 		  }
4374 	    }
4375 	  line = line->Next;
4376       }
4377     polyg = geom->FirstPolygon;
4378     while (polyg)
4379       {
4380 	  if (type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION
4381 	      || type == GAIA_MULTIPOLYGONZ || type == GAIA_GEOMETRYCOLLECTIONZ
4382 	      || type == GAIA_MULTIPOLYGONM || type == GAIA_GEOMETRYCOLLECTIONM
4383 	      || type == GAIA_MULTIPOLYGONZM
4384 	      || type == GAIA_GEOMETRYCOLLECTIONZM)
4385 	    {
4386 		*ptr = 0x01;
4387 		/* it's a collection: the CLASS TYPE for this element */
4388 		if (type == GAIA_MULTIPOLYGONZ
4389 		    || type == GAIA_GEOMETRYCOLLECTIONZ)
4390 		    gaiaExport32 (ptr + 1, GAIA_POLYGONZ, 1, endian_arch);
4391 		else if (type == GAIA_MULTIPOLYGONM
4392 			 || type == GAIA_GEOMETRYCOLLECTIONM)
4393 		    gaiaExport32 (ptr + 1, GAIA_POLYGONM, 1, endian_arch);
4394 		else if (type == GAIA_MULTIPOLYGONZM
4395 			 || type == GAIA_GEOMETRYCOLLECTIONZM)
4396 		    gaiaExport32 (ptr + 1, GAIA_POLYGONZM, 1, endian_arch);
4397 		else
4398 		    gaiaExport32 (ptr + 1, GAIA_POLYGON, 1, endian_arch);
4399 		ptr += 5;
4400 	    }
4401 	  gaiaExport32 (ptr, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
4402 	  rng = polyg->Exterior;
4403 	  gaiaExport32 (ptr + 4, rng->Points, 1, endian_arch);	/* # points - exterior ring */
4404 	  ptr += 8;
4405 	  for (iv = 0; iv < rng->Points; iv++)
4406 	    {
4407 		if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ
4408 		    || type == GAIA_GEOMETRYCOLLECTIONZ)
4409 		  {
4410 		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
4411 		  }
4412 		else if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM
4413 			 || type == GAIA_GEOMETRYCOLLECTIONM)
4414 		  {
4415 		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
4416 		  }
4417 		else if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM
4418 			 || type == GAIA_GEOMETRYCOLLECTIONZM)
4419 		  {
4420 		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
4421 		  }
4422 		else
4423 		  {
4424 		      gaiaGetPoint (rng->Coords, iv, &x, &y);
4425 		  }
4426 		gaiaExport64 (ptr, x, 1, endian_arch);	/* X - exterior ring */
4427 		gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - exterior ring */
4428 		ptr += 16;
4429 		if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ
4430 		    || type == GAIA_GEOMETRYCOLLECTIONZ)
4431 		  {
4432 		      gaiaExport64 (ptr, z, 1, endian_arch);	/* Z - exterior ring */
4433 		      ptr += 8;
4434 		  }
4435 		if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM
4436 		    || type == GAIA_GEOMETRYCOLLECTIONM)
4437 		  {
4438 		      gaiaExport64 (ptr, m, 1, endian_arch);	/* M - exterior ring */
4439 		      ptr += 8;
4440 		  }
4441 		if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM
4442 		    || type == GAIA_GEOMETRYCOLLECTIONZM)
4443 		  {
4444 		      gaiaExport64 (ptr, z, 1, endian_arch);	/* Z - exterior ring */
4445 		      gaiaExport64 (ptr + 8, m, 1, endian_arch);	/* M - exterior ring */
4446 		      ptr += 16;
4447 		  }
4448 	    }
4449 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
4450 	    {
4451 		rng = polyg->Interiors + ib;
4452 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
4453 		ptr += 4;
4454 		for (iv = 0; iv < rng->Points; iv++)
4455 		  {
4456 		      if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ
4457 			  || type == GAIA_GEOMETRYCOLLECTIONZ)
4458 			{
4459 			    gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
4460 			}
4461 		      else if (type == GAIA_POLYGONM
4462 			       || type == GAIA_MULTIPOLYGONM
4463 			       || type == GAIA_GEOMETRYCOLLECTIONM)
4464 			{
4465 			    gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
4466 			}
4467 		      else if (type == GAIA_POLYGONZM
4468 			       || type == GAIA_MULTIPOLYGONZM
4469 			       || type == GAIA_GEOMETRYCOLLECTIONZM)
4470 			{
4471 			    gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
4472 			}
4473 		      else
4474 			{
4475 			    gaiaGetPoint (rng->Coords, iv, &x, &y);
4476 			}
4477 		      gaiaExport64 (ptr, x, 1, endian_arch);	/* X - interior ring */
4478 		      gaiaExport64 (ptr + 8, y, 1, endian_arch);	/* Y - interior ring */
4479 		      ptr += 16;
4480 		      if (type == GAIA_POLYGONZ || type == GAIA_MULTIPOLYGONZ
4481 			  || type == GAIA_GEOMETRYCOLLECTIONZ)
4482 			{
4483 			    gaiaExport64 (ptr, z, 1, endian_arch);	/* Z - exterior ring */
4484 			    ptr += 8;
4485 			}
4486 		      if (type == GAIA_POLYGONM || type == GAIA_MULTIPOLYGONM
4487 			  || type == GAIA_GEOMETRYCOLLECTIONM)
4488 			{
4489 			    gaiaExport64 (ptr, m, 1, endian_arch);	/* M - exterior ring */
4490 			    ptr += 8;
4491 			}
4492 		      if (type == GAIA_POLYGONZM || type == GAIA_MULTIPOLYGONZM
4493 			  || type == GAIA_GEOMETRYCOLLECTIONZM)
4494 			{
4495 			    gaiaExport64 (ptr, z, 1, endian_arch);	/* Z - exterior ring */
4496 			    gaiaExport64 (ptr + 8, m, 1, endian_arch);	/* M - exterior ring */
4497 			    ptr += 16;
4498 			}
4499 		  }
4500 	    }
4501 	  polyg = polyg->Next;
4502       }
4503 }
4504 
4505 GAIAGEO_DECLARE int
gaiaEwkbGetPoint(gaiaGeomCollPtr geom,unsigned char * blob,int offset,int blob_size,int endian,int endian_arch,int dims)4506 gaiaEwkbGetPoint (gaiaGeomCollPtr geom, unsigned char *blob,
4507 		  int offset, int blob_size, int endian, int endian_arch,
4508 		  int dims)
4509 {
4510 /* decodes a POINT from PostGIS EWKB binary GEOMETRY */
4511     double x;
4512     double y;
4513     double z;
4514     double m;
4515     switch (dims)
4516       {
4517       case GAIA_XY_Z_M:
4518 	  if (blob_size < offset + 32)
4519 	      return -1;
4520 	  break;
4521       case GAIA_XY_Z:
4522       case GAIA_XY_M:
4523 	  if (blob_size < offset + 24)
4524 	      return -1;
4525 	  break;
4526       default:
4527 	  if (blob_size < offset + 16)
4528 	      return -1;
4529 	  break;
4530       }
4531     x = gaiaImport64 (blob + offset, endian, endian_arch);
4532     offset += 8;
4533     y = gaiaImport64 (blob + offset, endian, endian_arch);
4534     offset += 8;
4535     if (dims == GAIA_XY_Z_M)
4536       {
4537 	  z = gaiaImport64 (blob + offset, endian, endian_arch);
4538 	  offset += 8;
4539 	  m = gaiaImport64 (blob + offset, endian, endian_arch);
4540 	  offset += 8;
4541 	  gaiaAddPointToGeomCollXYZM (geom, x, y, z, m);
4542       }
4543     else if (dims == GAIA_XY_Z)
4544       {
4545 	  z = gaiaImport64 (blob + offset, endian, endian_arch);
4546 	  offset += 8;
4547 	  gaiaAddPointToGeomCollXYZ (geom, x, y, z);
4548       }
4549     else if (dims == GAIA_XY_M)
4550       {
4551 	  m = gaiaImport64 (blob + offset, endian, endian_arch);
4552 	  offset += 8;
4553 	  gaiaAddPointToGeomCollXYM (geom, x, y, m);
4554       }
4555     else
4556 	gaiaAddPointToGeomColl (geom, x, y);
4557     return offset;
4558 }
4559 
4560 GAIAGEO_DECLARE int
gaiaEwkbGetLinestring(gaiaGeomCollPtr geom,unsigned char * blob,int offset,int blob_size,int endian,int endian_arch,int dims)4561 gaiaEwkbGetLinestring (gaiaGeomCollPtr geom, unsigned char *blob,
4562 		       int offset, int blob_size, int endian,
4563 		       int endian_arch, int dims)
4564 {
4565 /* decodes a LINESTRING from PostGIS binary GEOMETRY */
4566     int npoints;
4567     int iv;
4568     double x;
4569     double y;
4570     double z;
4571     double m;
4572     gaiaLinestringPtr ln;
4573     if (blob_size < offset + 4)
4574 	return -1;
4575     npoints = gaiaImport32 (blob + offset, endian, endian_arch);
4576     offset += 4;
4577     switch (dims)
4578       {
4579       case GAIA_XY_Z_M:
4580 	  if (blob_size < offset + (32 * npoints))
4581 	      return -1;
4582 	  break;
4583       case GAIA_XY_Z:
4584       case GAIA_XY_M:
4585 	  if (blob_size < offset + (24 * npoints))
4586 	      return -1;
4587 	  break;
4588       default:
4589 	  if (blob_size < offset + (16 * npoints))
4590 	      return -1;
4591 	  break;
4592       }
4593     ln = gaiaAddLinestringToGeomColl (geom, npoints);
4594     for (iv = 0; iv < npoints; iv++)
4595       {
4596 	  x = gaiaImport64 (blob + offset, endian, endian_arch);
4597 	  offset += 8;
4598 	  y = gaiaImport64 (blob + offset, endian, endian_arch);
4599 	  offset += 8;
4600 	  if (dims == GAIA_XY_Z_M)
4601 	    {
4602 		z = gaiaImport64 (blob + offset, endian, endian_arch);
4603 		offset += 8;
4604 		m = gaiaImport64 (blob + offset, endian, endian_arch);
4605 		offset += 8;
4606 		gaiaSetPointXYZM (ln->Coords, iv, x, y, z, m);
4607 	    }
4608 	  else if (dims == GAIA_XY_Z)
4609 	    {
4610 		z = gaiaImport64 (blob + offset, endian, endian_arch);
4611 		offset += 8;
4612 		gaiaSetPointXYZ (ln->Coords, iv, x, y, z);
4613 	    }
4614 	  else if (dims == GAIA_XY_M)
4615 	    {
4616 		m = gaiaImport64 (blob + offset, endian, endian_arch);
4617 		offset += 8;
4618 		gaiaSetPointXYM (ln->Coords, iv, x, y, m);
4619 	    }
4620 	  else
4621 	      gaiaSetPoint (ln->Coords, iv, x, y);
4622       }
4623     return offset;
4624 }
4625 
4626 GAIAGEO_DECLARE int
gaiaEwkbGetPolygon(gaiaGeomCollPtr geom,unsigned char * blob,int offset,int blob_size,int endian,int endian_arch,int dims)4627 gaiaEwkbGetPolygon (gaiaGeomCollPtr geom, unsigned char *blob,
4628 		    int offset, int blob_size, int endian,
4629 		    int endian_arch, int dims)
4630 {
4631 /* decodes a POLYGON from PostGIS binary GEOMETRY */
4632     int rings;
4633     int npoints;
4634     int iv;
4635     int ib;
4636     double x;
4637     double y;
4638     double z;
4639     double m;
4640     gaiaPolygonPtr polyg = NULL;
4641     gaiaRingPtr rng;
4642     if (blob_size < offset + 4)
4643 	return -1;
4644     rings = gaiaImport32 (blob + offset, endian, endian_arch);
4645     offset += 4;
4646     for (ib = 0; ib < rings; ib++)
4647       {
4648 	  if (blob_size < offset + 4)
4649 	      return -1;
4650 	  npoints = gaiaImport32 (blob + offset, endian, endian_arch);
4651 	  offset += 4;
4652 	  switch (dims)
4653 	    {
4654 	    case GAIA_XY_Z_M:
4655 		if (blob_size < offset + (32 * npoints))
4656 		    return -1;
4657 		break;
4658 	    case GAIA_XY_Z:
4659 	    case GAIA_XY_M:
4660 		if (blob_size < offset + (24 * npoints))
4661 		    return -1;
4662 		break;
4663 	    default:
4664 		if (blob_size < offset + (16 * npoints))
4665 		    return -1;
4666 		break;
4667 	    }
4668 	  if (ib == 0)
4669 	    {
4670 		polyg = gaiaAddPolygonToGeomColl (geom, npoints, rings - 1);
4671 		rng = polyg->Exterior;
4672 	    }
4673 	  else
4674 	      rng = gaiaAddInteriorRing (polyg, ib - 1, npoints);
4675 	  for (iv = 0; iv < npoints; iv++)
4676 	    {
4677 		x = gaiaImport64 (blob + offset, endian, endian_arch);
4678 		offset += 8;
4679 		y = gaiaImport64 (blob + offset, endian, endian_arch);
4680 		offset += 8;
4681 		if (dims == GAIA_XY_Z_M)
4682 		  {
4683 		      z = gaiaImport64 (blob + offset, endian, endian_arch);
4684 		      offset += 8;
4685 		      m = gaiaImport64 (blob + offset, endian, endian_arch);
4686 		      offset += 8;
4687 		      gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
4688 		  }
4689 		else if (dims == GAIA_XY_Z)
4690 		  {
4691 		      z = gaiaImport64 (blob + offset, endian, endian_arch);
4692 		      offset += 8;
4693 		      gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
4694 		  }
4695 		else if (dims == GAIA_XY_M)
4696 		  {
4697 		      m = gaiaImport64 (blob + offset, endian, endian_arch);
4698 		      offset += 8;
4699 		      gaiaSetPointXYM (rng->Coords, iv, x, y, m);
4700 		  }
4701 		else
4702 		    gaiaSetPoint (rng->Coords, iv, x, y);
4703 	    }
4704       }
4705     return offset;
4706 }
4707 
4708 GAIAGEO_DECLARE int
gaiaEwkbGetMultiGeometry(gaiaGeomCollPtr geom,unsigned char * blob,int offset,int blob_size,int endian,int endian_arch,int dims)4709 gaiaEwkbGetMultiGeometry (gaiaGeomCollPtr geom, unsigned char *blob,
4710 			  int offset, int blob_size, int endian,
4711 			  int endian_arch, int dims)
4712 {
4713 /* decodes a MultiGeometry from PostGIS EWKB binary GEOMETRY */
4714     int entities;
4715     int type;
4716     unsigned char xtype[4];
4717     int ie;
4718     int off;
4719     if (blob_size < offset + 4)
4720 	return -1;
4721     entities = gaiaImport32 (blob + offset, endian, endian_arch);
4722     offset += 4;
4723     for (ie = 0; ie < entities; ie++)
4724       {
4725 	  if (blob_size < offset + 5)
4726 	      return -1;
4727 	  memcpy (xtype, blob + offset + 1, 4);
4728 	  if (endian)
4729 	      xtype[3] = 0x00;
4730 	  else
4731 	      xtype[0] = 0x00;
4732 	  type = gaiaImport32 (xtype, endian, endian_arch);
4733 	  offset += 5;
4734 	  switch (type)
4735 	    {
4736 	    case GAIA_POINT:
4737 		off =
4738 		    gaiaEwkbGetPoint (geom, blob, offset, blob_size, endian,
4739 				      endian_arch, dims);
4740 		if (off < 0)
4741 		    return -1;
4742 		offset = off;
4743 		break;
4744 	    case GAIA_LINESTRING:
4745 		off =
4746 		    gaiaEwkbGetLinestring (geom, blob, offset, blob_size,
4747 					   endian, endian_arch, dims);
4748 		if (off < 0)
4749 		    return -1;
4750 		offset = off;
4751 		break;
4752 	    case GAIA_POLYGON:
4753 		off =
4754 		    gaiaEwkbGetPolygon (geom, blob, offset, blob_size, endian,
4755 					endian_arch, dims);
4756 		if (off < 0)
4757 		    return -1;
4758 		offset = off;
4759 		break;
4760 	    default:		/* unexpected: invalid EWKB */
4761 		return -1;
4762 	    };
4763       }
4764     return offset;
4765 }
4766 
4767 static int
parseHexEwkbByte(const unsigned char high,const unsigned char low,unsigned char * byte)4768 parseHexEwkbByte (const unsigned char high, const unsigned char low,
4769 		  unsigned char *byte)
4770 {
4771 /* parsing an Hexadecimal byte */
4772     unsigned char hex;
4773     switch (high)
4774       {
4775       case '0':
4776 	  hex = 16 * 0;
4777 	  break;
4778       case '1':
4779 	  hex = 16 * 1;
4780 	  break;
4781       case '2':
4782 	  hex = 16 * 2;
4783 	  break;
4784       case '3':
4785 	  hex = 16 * 3;
4786 	  break;
4787       case '4':
4788 	  hex = 16 * 4;
4789 	  break;
4790       case '5':
4791 	  hex = 16 * 5;
4792 	  break;
4793       case '6':
4794 	  hex = 16 * 6;
4795 	  break;
4796       case '7':
4797 	  hex = 16 * 7;
4798 	  break;
4799       case '8':
4800 	  hex = 16 * 8;
4801 	  break;
4802       case '9':
4803 	  hex = 16 * 9;
4804 	  break;
4805       case 'A':
4806       case 'a':
4807 	  hex = 16 * 10;
4808 	  break;
4809       case 'B':
4810       case 'b':
4811 	  hex = 16 * 11;
4812 	  break;
4813       case 'C':
4814       case 'c':
4815 	  hex = 16 * 12;
4816 	  break;
4817       case 'D':
4818       case 'd':
4819 	  hex = 16 * 13;
4820 	  break;
4821       case 'E':
4822       case 'e':
4823 	  hex = 16 * 14;
4824 	  break;
4825       case 'F':
4826       case 'f':
4827 	  hex = 16 * 15;
4828 	  break;
4829       default:
4830 	  return 0;
4831       };
4832     switch (low)
4833       {
4834       case '0':
4835 	  hex += 0;
4836 	  break;
4837       case '1':
4838 	  hex += 1;
4839 	  break;
4840       case '2':
4841 	  hex += 2;
4842 	  break;
4843       case '3':
4844 	  hex += 3;
4845 	  break;
4846       case '4':
4847 	  hex += 4;
4848 	  break;
4849       case '5':
4850 	  hex += 5;
4851 	  break;
4852       case '6':
4853 	  hex += 6;
4854 	  break;
4855       case '7':
4856 	  hex += 7;
4857 	  break;
4858       case '8':
4859 	  hex += 8;
4860 	  break;
4861       case '9':
4862 	  hex += 9;
4863 	  break;
4864       case 'A':
4865       case 'a':
4866 	  hex += 10;
4867 	  break;
4868       case 'B':
4869       case 'b':
4870 	  hex += 11;
4871 	  break;
4872       case 'C':
4873       case 'c':
4874 	  hex += 12;
4875 	  break;
4876       case 'D':
4877       case 'd':
4878 	  hex += 13;
4879 	  break;
4880       case 'E':
4881       case 'e':
4882 	  hex += 14;
4883 	  break;
4884       case 'F':
4885       case 'f':
4886 	  hex += 15;
4887 	  break;
4888       default:
4889 	  return 0;
4890       };
4891     *byte = hex;
4892     return 1;
4893 }
4894 
4895 GAIAGEO_DECLARE unsigned char *
gaiaParseHexEWKB(const unsigned char * blob_hex,int * blob_size)4896 gaiaParseHexEWKB (const unsigned char *blob_hex, int *blob_size)
4897 {
4898 /* parsing an Hexadecimal EWKB Geometry */
4899     unsigned char *blob;
4900     unsigned char *p_out;
4901     const unsigned char *p_in;
4902     char high;
4903     char low;
4904     unsigned char hex;
4905     int size;
4906     int len = strlen ((const char *) blob_hex);
4907     size = len / 2;
4908     if (size * 2 != len)
4909 	return NULL;
4910     blob = malloc (size);
4911     if (!blob)
4912 	return NULL;
4913     *blob_size = size;
4914     p_in = blob_hex;
4915     p_out = blob;
4916     while (*p_in != '\0')
4917       {
4918 	  high = *p_in++;
4919 	  low = *p_in++;
4920 	  if (!parseHexEwkbByte (high, low, &hex))
4921 	    {
4922 		free (blob);
4923 		return NULL;
4924 	    }
4925 	  *p_out++ = hex;
4926       }
4927     *blob_size = size;
4928     return blob;
4929 }
4930 
4931 gaiaGeomCollPtr
gaiaFromEWKB(const unsigned char * in_buffer)4932 gaiaFromEWKB (const unsigned char *in_buffer)
4933 {
4934 /* creates a Gaia own Geometry from GEOS/PostGIS EWKB */
4935     unsigned char *blob;
4936     int blob_size;
4937     unsigned char xtype[4];
4938     unsigned char xdims;
4939     int type;
4940     int has_z = 0;
4941     int has_m = 0;
4942     int dims = GAIA_XY;
4943     int srid;
4944     int ret;
4945     int endian;
4946     int endian_arch = gaiaEndianArch ();
4947     gaiaGeomCollPtr geom = NULL;
4948     blob = gaiaParseHexEWKB (in_buffer, &blob_size);
4949     if (!blob)
4950 	return NULL;
4951     if (blob_size < 9)
4952       {
4953 	  free (blob);
4954 	  return NULL;
4955       }
4956     if (*(blob + 0) == 0x01)
4957 	endian = 1;
4958     else
4959 	endian = 0;
4960     memcpy (xtype, blob + 1, 4);
4961     if (endian)
4962       {
4963 	  xdims = xtype[3];
4964 	  xtype[3] = 0x00;
4965       }
4966     else
4967       {
4968 	  xdims = xtype[0];
4969 	  xtype[0] = 0x00;
4970       }
4971     type = gaiaImport32 (xtype, endian, endian_arch);
4972     if (xdims & 0x40)
4973 	has_m = 1;
4974     if (xdims & 0x80)
4975 	has_z = 1;
4976     if (has_m && has_z)
4977       {
4978 	  dims = GAIA_XY_Z_M;
4979 	  geom = gaiaAllocGeomCollXYZM ();
4980       }
4981     else if (has_m)
4982       {
4983 	  dims = GAIA_XY_M;
4984 	  geom = gaiaAllocGeomCollXYM ();
4985       }
4986     else if (has_z)
4987       {
4988 	  dims = GAIA_XY_Z;
4989 	  geom = gaiaAllocGeomCollXYZ ();
4990       }
4991     else
4992       {
4993 	  dims = GAIA_XY;
4994 	  geom = gaiaAllocGeomColl ();
4995       }
4996     srid = gaiaImport32 (blob + 5, endian, endian_arch);
4997     geom->Srid = srid;
4998     if (geom->Srid <= 0)
4999 	geom->Srid = 0;
5000     switch (type)
5001       {
5002       case GAIA_POINT:
5003 	  ret =
5004 	      gaiaEwkbGetPoint (geom, blob, 9, blob_size, endian, endian_arch,
5005 				dims);
5006 	  break;
5007       case GAIA_LINESTRING:
5008 	  ret =
5009 	      gaiaEwkbGetLinestring (geom, blob, 9, blob_size, endian,
5010 				     endian_arch, dims);
5011 	  break;
5012       case GAIA_POLYGON:
5013 	  ret =
5014 	      gaiaEwkbGetPolygon (geom, blob, 9, blob_size, endian, endian_arch,
5015 				  dims);
5016 	  break;
5017       default:
5018 	  ret =
5019 	      gaiaEwkbGetMultiGeometry (geom, blob, 9, blob_size, endian,
5020 					endian_arch, dims);
5021 	  break;
5022       };
5023     free (blob);
5024     if (ret < 0)
5025       {
5026 	  /* invalid EWKB !!! */
5027 	  gaiaFreeGeomColl (geom);
5028 	  return NULL;
5029       }
5030     return geom;
5031 }
5032 
5033 GAIAGEO_DECLARE void
gaiaToEWKB(gaiaOutBufferPtr out_buf,gaiaGeomCollPtr geom)5034 gaiaToEWKB (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom)
5035 {
5036 /* prints the GEOS/PostGIS EWKB text representation of current geometry */
5037     char buf[2048];
5038     unsigned char endian_buf[16];
5039     char byte[3];
5040     char *ptr;
5041     int size;
5042     int type;
5043     int entities = 0;
5044     int n_points = 0;
5045     int n_linestrings = 0;
5046     int n_polygons = 0;
5047     int i;
5048     int iv;
5049     int ib;
5050     double x;
5051     double y;
5052     double z;
5053     double m;
5054     int endian_arch = gaiaEndianArch ();
5055     gaiaPointPtr pt;
5056     gaiaLinestringPtr ln;
5057     gaiaPolygonPtr pg;
5058     gaiaRingPtr rng;
5059     gaiaPointPtr point = NULL;
5060     gaiaLinestringPtr line = NULL;
5061     gaiaPolygonPtr polyg = NULL;
5062 
5063 /* precomputing the required size */
5064     size = 5;			/* SRID and terminating '\0' */
5065     pt = geom->FirstPoint;
5066     while (pt)
5067       {
5068 	  point = pt;
5069 	  entities++;
5070 	  n_points++;
5071 	  pt = pt->Next;
5072       }
5073     ln = geom->FirstLinestring;
5074     while (ln)
5075       {
5076 	  line = ln;
5077 	  entities++;
5078 	  n_linestrings++;
5079 	  ln = ln->Next;
5080       }
5081     pg = geom->FirstPolygon;
5082     while (pg)
5083       {
5084 	  polyg = pg;
5085 	  entities++;
5086 	  n_polygons++;
5087 	  pg = pg->Next;
5088       }
5089     if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
5090 	return;
5091 /* ok, we can determine the geometry class */
5092     if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
5093       {
5094 	  if (geom->DeclaredType == GAIA_MULTIPOINT)
5095 	      type = GAIA_MULTIPOINT;
5096 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5097 	      type = GAIA_GEOMETRYCOLLECTION;
5098 	  else
5099 	      type = GAIA_POINT;
5100       }
5101     else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
5102       {
5103 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5104 	      type = GAIA_GEOMETRYCOLLECTION;
5105 	  else
5106 	      type = GAIA_MULTIPOINT;
5107       }
5108     else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
5109       {
5110 	  if (geom->DeclaredType == GAIA_MULTILINESTRING)
5111 	      type = GAIA_MULTILINESTRING;
5112 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5113 	      type = GAIA_GEOMETRYCOLLECTION;
5114 	  else
5115 	      type = GAIA_LINESTRING;
5116       }
5117     else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
5118       {
5119 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5120 	      type = GAIA_GEOMETRYCOLLECTION;
5121 	  else
5122 	      type = GAIA_MULTILINESTRING;
5123       }
5124     else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
5125       {
5126 	  if (geom->DeclaredType == GAIA_MULTIPOLYGON)
5127 	      type = GAIA_MULTIPOLYGON;
5128 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5129 	      type = GAIA_GEOMETRYCOLLECTION;
5130 	  else
5131 	      type = GAIA_POLYGON;
5132       }
5133     else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
5134       {
5135 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5136 	      type = GAIA_GEOMETRYCOLLECTION;
5137 	  else
5138 	      type = GAIA_MULTIPOLYGON;
5139       }
5140     else
5141 	type = GAIA_GEOMETRYCOLLECTION;
5142 /* and now we compute the size of EWKB */
5143     size += 10;			/* header size */
5144     if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5145 	|| type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5146 	size += 8;
5147     point = geom->FirstPoint;
5148     while (point)
5149       {
5150 	  if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5151 	      || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5152 	      size += 10;
5153 	  if (geom->DimensionModel == GAIA_XY_Z
5154 	      || geom->DimensionModel == GAIA_XY_M)
5155 	      size += 48;	/* three doubles for each POINT */
5156 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
5157 	      size += 64;	/* four doubles for each POINT */
5158 	  else
5159 	      size += 32;	/* two doubles for each POINT */
5160 	  point = point->Next;
5161       }
5162     line = geom->FirstLinestring;
5163     while (line)
5164       {
5165 	  if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5166 	      || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5167 	      size += 10;
5168 	  if (geom->DimensionModel == GAIA_XY_Z
5169 	      || geom->DimensionModel == GAIA_XY_M)
5170 	      size += 8 + (line->Points * 48);	/* three doubles for each VERTEX */
5171 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
5172 	      size += 8 + (line->Points * 64);	/* four doubles for each VERTEX */
5173 	  else
5174 	      size += 8 + (line->Points * 32);	/* two doubles for each VERTEX */
5175 	  line = line->Next;
5176       }
5177     polyg = geom->FirstPolygon;
5178     while (polyg)
5179       {
5180 	  if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5181 	      || type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5182 	      size += 10;
5183 	  rng = polyg->Exterior;
5184 	  if (geom->DimensionModel == GAIA_XY_Z
5185 	      || geom->DimensionModel == GAIA_XY_M)
5186 	      size += 16 + (rng->Points * 48);	/* three doubles for each VERTEX */
5187 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
5188 	      size += 16 + (rng->Points * 64);	/* four doubles for each VERTEX */
5189 	  else
5190 	      size += 16 + (rng->Points * 32);	/* two doubles for each VERTEX */
5191 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
5192 	    {
5193 		rng = polyg->Interiors + ib;
5194 		if (geom->DimensionModel == GAIA_XY_Z
5195 		    || geom->DimensionModel == GAIA_XY_M)
5196 		    size += 8 + (rng->Points * 48);	/* three doubles for each VERTEX */
5197 		else if (geom->DimensionModel == GAIA_XY_Z_M)
5198 		    size += 8 + (rng->Points * 64);	/* four doubles for each VERTEX */
5199 		else
5200 		    size += 8 + (rng->Points * 32);	/* two doubles for each VERTEX */
5201 	    }
5202 	  polyg = polyg->Next;
5203       }
5204 /* and finally we build the EWKB expression */
5205     ptr = buf;
5206     *ptr++ = '0';		/* little endian byte order */
5207     *ptr++ = '1';
5208     gaiaExport32 (endian_buf, type, 1, endian_arch);	/* the main CLASS TYPE */
5209     for (i = 0; i < 3; i++)
5210       {
5211 	  /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */
5212 	  sprintf (byte, "%02X", endian_buf[i]);
5213 	  *ptr++ = byte[0];
5214 	  *ptr++ = byte[1];
5215       }
5216 /* marking dimensions and M/Z presence */
5217     if (geom->DimensionModel == GAIA_XY_Z)
5218       {
5219 	  *ptr++ = 'A';
5220 	  *ptr++ = '0';
5221       }
5222     else if (geom->DimensionModel == GAIA_XY_M)
5223       {
5224 	  *ptr++ = '6';
5225 	  *ptr++ = '0';
5226       }
5227     else if (geom->DimensionModel == GAIA_XY_Z_M)
5228       {
5229 	  *ptr++ = 'E';
5230 	  *ptr++ = '0';
5231       }
5232     else
5233       {
5234 	  *ptr++ = '2';
5235 	  *ptr++ = '0';
5236       }
5237     gaiaExport32 (endian_buf, geom->Srid, 1, endian_arch);
5238     for (i = 0; i < 4; i++)
5239       {
5240 	  sprintf (byte, "%02X", endian_buf[i]);
5241 	  *ptr++ = byte[0];
5242 	  *ptr++ = byte[1];
5243       }
5244     *ptr++ = '\0';
5245     gaiaAppendToOutBuffer (out_buf, buf);
5246     ptr = buf;
5247     if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
5248 	|| type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5249       {
5250 	  gaiaExport32 (endian_buf, entities, 1, endian_arch);	/* it's a collection; # entities */
5251 	  for (i = 0; i < 4; i++)
5252 	    {
5253 		sprintf (byte, "%02X", endian_buf[i]);
5254 		*ptr++ = byte[0];
5255 		*ptr++ = byte[1];
5256 	    }
5257       }
5258     point = geom->FirstPoint;
5259     while (point)
5260       {
5261 	  if ((ptr - buf) > 1024)
5262 	    {
5263 		/* flushing the internal buffer */
5264 		*ptr++ = '\0';
5265 		gaiaAppendToOutBuffer (out_buf, buf);
5266 		ptr = buf;
5267 	    }
5268 	  if (type == GAIA_MULTIPOINT || type == GAIA_GEOMETRYCOLLECTION)
5269 	    {
5270 		*ptr++ = '0';
5271 		*ptr++ = '1';
5272 		/* it's a collection: the CLASS TYPE for this element */
5273 		gaiaExport32 (endian_buf, GAIA_POINT, 1, endian_arch);
5274 		for (i = 0; i < 3; i++)
5275 		  {
5276 		      /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */
5277 		      sprintf (byte, "%02X", endian_buf[i]);
5278 		      *ptr++ = byte[0];
5279 		      *ptr++ = byte[1];
5280 		  }
5281 		/* marking M/Z presence */
5282 		if (geom->DimensionModel == GAIA_XY_Z)
5283 		    *ptr++ = '8';
5284 		else if (geom->DimensionModel == GAIA_XY_M)
5285 		    *ptr++ = '4';
5286 		else if (geom->DimensionModel == GAIA_XY_Z_M)
5287 		    *ptr++ = 'C';
5288 		else
5289 		    *ptr++ = '0';
5290 		*ptr++ = '0';
5291 	    }
5292 	  gaiaExport64 (endian_buf, point->X, 1, endian_arch);	/* X */
5293 	  for (i = 0; i < 8; i++)
5294 	    {
5295 		sprintf (byte, "%02X", endian_buf[i]);
5296 		*ptr++ = byte[0];
5297 		*ptr++ = byte[1];
5298 	    }
5299 	  gaiaExport64 (endian_buf, point->Y, 1, endian_arch);	/* Y */
5300 	  for (i = 0; i < 8; i++)
5301 	    {
5302 		sprintf (byte, "%02X", endian_buf[i]);
5303 		*ptr++ = byte[0];
5304 		*ptr++ = byte[1];
5305 	    }
5306 	  if (geom->DimensionModel == GAIA_XY_Z)
5307 	    {
5308 		gaiaExport64 (endian_buf, point->Z, 1, endian_arch);	/* Z */
5309 		for (i = 0; i < 8; i++)
5310 		  {
5311 		      sprintf (byte, "%02X", endian_buf[i]);
5312 		      *ptr++ = byte[0];
5313 		      *ptr++ = byte[1];
5314 		  }
5315 	    }
5316 	  else if (geom->DimensionModel == GAIA_XY_M)
5317 	    {
5318 		gaiaExport64 (endian_buf, point->M, 1, endian_arch);	/* M */
5319 		for (i = 0; i < 8; i++)
5320 		  {
5321 		      sprintf (byte, "%02X", endian_buf[i]);
5322 		      *ptr++ = byte[0];
5323 		      *ptr++ = byte[1];
5324 		  }
5325 	    }
5326 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
5327 	    {
5328 		gaiaExport64 (endian_buf, point->Z, 1, endian_arch);	/* Z */
5329 		for (i = 0; i < 8; i++)
5330 		  {
5331 		      sprintf (byte, "%02X", endian_buf[i]);
5332 		      *ptr++ = byte[0];
5333 		      *ptr++ = byte[1];
5334 		  }
5335 		gaiaExport64 (endian_buf, point->M, 1, endian_arch);	/* M */
5336 		for (i = 0; i < 8; i++)
5337 		  {
5338 		      sprintf (byte, "%02X", endian_buf[i]);
5339 		      *ptr++ = byte[0];
5340 		      *ptr++ = byte[1];
5341 		  }
5342 	    }
5343 	  point = point->Next;
5344       }
5345     line = geom->FirstLinestring;
5346     while (line)
5347       {
5348 	  if ((ptr - buf) > 1024)
5349 	    {
5350 		/* flushing the internal buffer */
5351 		*ptr++ = '\0';
5352 		gaiaAppendToOutBuffer (out_buf, buf);
5353 		ptr = buf;
5354 	    }
5355 	  if (type == GAIA_MULTILINESTRING || type == GAIA_GEOMETRYCOLLECTION)
5356 	    {
5357 		*ptr++ = '0';
5358 		*ptr++ = '1';
5359 		/* it's a collection: the CLASS TYPE for this element */
5360 		gaiaExport32 (endian_buf, GAIA_LINESTRING, 1, endian_arch);
5361 		for (i = 0; i < 3; i++)
5362 		  {
5363 		      /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */
5364 		      sprintf (byte, "%02X", endian_buf[i]);
5365 		      *ptr++ = byte[0];
5366 		      *ptr++ = byte[1];
5367 		  }
5368 		/* marking M/Z presence */
5369 		if (geom->DimensionModel == GAIA_XY_Z)
5370 		    *ptr++ = '8';
5371 		else if (geom->DimensionModel == GAIA_XY_M)
5372 		    *ptr++ = '4';
5373 		else if (geom->DimensionModel == GAIA_XY_Z_M)
5374 		    *ptr++ = 'C';
5375 		else
5376 		    *ptr++ = '0';
5377 		*ptr++ = '0';
5378 	    }
5379 	  gaiaExport32 (endian_buf, line->Points, 1, endian_arch);	/* # points */
5380 	  for (i = 0; i < 4; i++)
5381 	    {
5382 		sprintf (byte, "%02X", endian_buf[i]);
5383 		*ptr++ = byte[0];
5384 		*ptr++ = byte[1];
5385 	    }
5386 	  for (iv = 0; iv < line->Points; iv++)
5387 	    {
5388 		if ((ptr - buf) > 1024)
5389 		  {
5390 		      /* flushing the internal buffer */
5391 		      *ptr++ = '\0';
5392 		      gaiaAppendToOutBuffer (out_buf, buf);
5393 		      ptr = buf;
5394 		  }
5395 		gaiaLineGetPoint (line, iv, &x, &y, &z, &m);
5396 		gaiaExport64 (endian_buf, x, 1, endian_arch);	/* X */
5397 		for (i = 0; i < 8; i++)
5398 		  {
5399 		      sprintf (byte, "%02X", endian_buf[i]);
5400 		      *ptr++ = byte[0];
5401 		      *ptr++ = byte[1];
5402 		  }
5403 		gaiaExport64 (endian_buf, y, 1, endian_arch);	/* Y */
5404 		for (i = 0; i < 8; i++)
5405 		  {
5406 		      sprintf (byte, "%02X", endian_buf[i]);
5407 		      *ptr++ = byte[0];
5408 		      *ptr++ = byte[1];
5409 		  }
5410 		if (geom->DimensionModel == GAIA_XY_Z)
5411 		  {
5412 		      gaiaExport64 (endian_buf, z, 1, endian_arch);	/* Z */
5413 		      for (i = 0; i < 8; i++)
5414 			{
5415 			    sprintf (byte, "%02X", endian_buf[i]);
5416 			    *ptr++ = byte[0];
5417 			    *ptr++ = byte[1];
5418 			}
5419 		  }
5420 		else if (geom->DimensionModel == GAIA_XY_M)
5421 		  {
5422 		      gaiaExport64 (endian_buf, m, 1, endian_arch);	/* M */
5423 		      for (i = 0; i < 8; i++)
5424 			{
5425 			    sprintf (byte, "%02X", endian_buf[i]);
5426 			    *ptr++ = byte[0];
5427 			    *ptr++ = byte[1];
5428 			}
5429 		  }
5430 		else if (geom->DimensionModel == GAIA_XY_Z_M)
5431 		  {
5432 		      gaiaExport64 (endian_buf, z, 1, endian_arch);	/* Z */
5433 		      for (i = 0; i < 8; i++)
5434 			{
5435 			    sprintf (byte, "%02X", endian_buf[i]);
5436 			    *ptr++ = byte[0];
5437 			    *ptr++ = byte[1];
5438 			}
5439 		      gaiaExport64 (endian_buf, m, 1, endian_arch);	/* M */
5440 		      for (i = 0; i < 8; i++)
5441 			{
5442 			    sprintf (byte, "%02X", endian_buf[i]);
5443 			    *ptr++ = byte[0];
5444 			    *ptr++ = byte[1];
5445 			}
5446 		  }
5447 	    }
5448 	  line = line->Next;
5449       }
5450     polyg = geom->FirstPolygon;
5451     while (polyg)
5452       {
5453 	  if ((ptr - buf) > 1024)
5454 	    {
5455 		/* flushing the internal buffer */
5456 		*ptr++ = '\0';
5457 		gaiaAppendToOutBuffer (out_buf, buf);
5458 		ptr = buf;
5459 	    }
5460 	  if (type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
5461 	    {
5462 		*ptr++ = '0';
5463 		*ptr++ = '1';
5464 		/* it's a collection: the CLASS TYPE for this element */
5465 		gaiaExport32 (endian_buf, GAIA_POLYGON, 1, endian_arch);
5466 		for (i = 0; i < 3; i++)
5467 		  {
5468 		      /* CAVEAT: the 4th byte in PostGIS encodes M/Z presence !!!! */
5469 		      sprintf (byte, "%02X", endian_buf[i]);
5470 		      *ptr++ = byte[0];
5471 		      *ptr++ = byte[1];
5472 		  }
5473 		/* marking M/Z presence */
5474 		if (geom->DimensionModel == GAIA_XY_Z)
5475 		    *ptr++ = '8';
5476 		else if (geom->DimensionModel == GAIA_XY_M)
5477 		    *ptr++ = '4';
5478 		else if (geom->DimensionModel == GAIA_XY_Z_M)
5479 		    *ptr++ = 'C';
5480 		else
5481 		    *ptr++ = '0';
5482 		*ptr++ = '0';
5483 	    }
5484 	  gaiaExport32 (endian_buf, polyg->NumInteriors + 1, 1, endian_arch);	/* # rings */
5485 	  for (i = 0; i < 4; i++)
5486 	    {
5487 		sprintf (byte, "%02X", endian_buf[i]);
5488 		*ptr++ = byte[0];
5489 		*ptr++ = byte[1];
5490 	    }
5491 	  rng = polyg->Exterior;
5492 	  gaiaExport32 (endian_buf, rng->Points, 1, endian_arch);	/* # points - exterior ring */
5493 	  for (i = 0; i < 4; i++)
5494 	    {
5495 		sprintf (byte, "%02X", endian_buf[i]);
5496 		*ptr++ = byte[0];
5497 		*ptr++ = byte[1];
5498 	    }
5499 	  for (iv = 0; iv < rng->Points; iv++)
5500 	    {
5501 		if ((ptr - buf) > 1024)
5502 		  {
5503 		      /* flushing the internal buffer */
5504 		      *ptr++ = '\0';
5505 		      gaiaAppendToOutBuffer (out_buf, buf);
5506 		      ptr = buf;
5507 		  }
5508 		gaiaRingGetPoint (rng, iv, &x, &y, &z, &m);
5509 		gaiaExport64 (endian_buf, x, 1, endian_arch);	/* X - exterior ring */
5510 		for (i = 0; i < 8; i++)
5511 		  {
5512 		      sprintf (byte, "%02X", endian_buf[i]);
5513 		      *ptr++ = byte[0];
5514 		      *ptr++ = byte[1];
5515 		  }
5516 		gaiaExport64 (endian_buf, y, 1, endian_arch);	/* Y - exterior ring */
5517 		for (i = 0; i < 8; i++)
5518 		  {
5519 		      sprintf (byte, "%02X", endian_buf[i]);
5520 		      *ptr++ = byte[0];
5521 		      *ptr++ = byte[1];
5522 		  }
5523 		if (geom->DimensionModel == GAIA_XY_Z)
5524 		  {
5525 		      gaiaExport64 (endian_buf, z, 1, endian_arch);	/* Z */
5526 		      for (i = 0; i < 8; i++)
5527 			{
5528 			    sprintf (byte, "%02X", endian_buf[i]);
5529 			    *ptr++ = byte[0];
5530 			    *ptr++ = byte[1];
5531 			}
5532 		  }
5533 		else if (geom->DimensionModel == GAIA_XY_M)
5534 		  {
5535 		      gaiaExport64 (endian_buf, m, 1, endian_arch);	/* M */
5536 		      for (i = 0; i < 8; i++)
5537 			{
5538 			    sprintf (byte, "%02X", endian_buf[i]);
5539 			    *ptr++ = byte[0];
5540 			    *ptr++ = byte[1];
5541 			}
5542 		  }
5543 		else if (geom->DimensionModel == GAIA_XY_Z_M)
5544 		  {
5545 		      gaiaExport64 (endian_buf, z, 1, endian_arch);	/* Z */
5546 		      for (i = 0; i < 8; i++)
5547 			{
5548 			    sprintf (byte, "%02X", endian_buf[i]);
5549 			    *ptr++ = byte[0];
5550 			    *ptr++ = byte[1];
5551 			}
5552 		      gaiaExport64 (endian_buf, m, 1, endian_arch);	/* M */
5553 		      for (i = 0; i < 8; i++)
5554 			{
5555 			    sprintf (byte, "%02X", endian_buf[i]);
5556 			    *ptr++ = byte[0];
5557 			    *ptr++ = byte[1];
5558 			}
5559 		  }
5560 	    }
5561 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
5562 	    {
5563 		rng = polyg->Interiors + ib;
5564 		gaiaExport32 (endian_buf, rng->Points, 1, endian_arch);	/* # points - interior ring */
5565 		for (i = 0; i < 4; i++)
5566 		  {
5567 		      sprintf (byte, "%02X", endian_buf[i]);
5568 		      *ptr++ = byte[0];
5569 		      *ptr++ = byte[1];
5570 		  }
5571 		for (iv = 0; iv < rng->Points; iv++)
5572 		  {
5573 		      if ((ptr - buf) > 1024)
5574 			{
5575 			    /* flushing the internal buffer */
5576 			    *ptr++ = '\0';
5577 			    gaiaAppendToOutBuffer (out_buf, buf);
5578 			    ptr = buf;
5579 			}
5580 		      gaiaRingGetPoint (rng, iv, &x, &y, &z, &m);
5581 		      gaiaExport64 (endian_buf, x, 1, endian_arch);	/* X - interior ring */
5582 		      for (i = 0; i < 8; i++)
5583 			{
5584 			    sprintf (byte, "%02X", endian_buf[i]);
5585 			    *ptr++ = byte[0];
5586 			    *ptr++ = byte[1];
5587 			}
5588 		      gaiaExport64 (endian_buf, y, 1, endian_arch);	/* Y - interior ring */
5589 		      for (i = 0; i < 8; i++)
5590 			{
5591 			    sprintf (byte, "%02X", endian_buf[i]);
5592 			    *ptr++ = byte[0];
5593 			    *ptr++ = byte[1];
5594 			}
5595 		      if (geom->DimensionModel == GAIA_XY_Z)
5596 			{
5597 			    gaiaExport64 (endian_buf, z, 1, endian_arch);	/* Z */
5598 			    for (i = 0; i < 8; i++)
5599 			      {
5600 				  sprintf (byte, "%02X", endian_buf[i]);
5601 				  *ptr++ = byte[0];
5602 				  *ptr++ = byte[1];
5603 			      }
5604 			}
5605 		      else if (geom->DimensionModel == GAIA_XY_M)
5606 			{
5607 			    gaiaExport64 (endian_buf, m, 1, endian_arch);	/* M */
5608 			    for (i = 0; i < 8; i++)
5609 			      {
5610 				  sprintf (byte, "%02X", endian_buf[i]);
5611 				  *ptr++ = byte[0];
5612 				  *ptr++ = byte[1];
5613 			      }
5614 			}
5615 		      else if (geom->DimensionModel == GAIA_XY_Z_M)
5616 			{
5617 			    gaiaExport64 (endian_buf, z, 1, endian_arch);	/* Z */
5618 			    for (i = 0; i < 8; i++)
5619 			      {
5620 				  sprintf (byte, "%02X", endian_buf[i]);
5621 				  *ptr++ = byte[0];
5622 				  *ptr++ = byte[1];
5623 			      }
5624 			    gaiaExport64 (endian_buf, m, 1, endian_arch);	/* M */
5625 			    for (i = 0; i < 8; i++)
5626 			      {
5627 				  sprintf (byte, "%02X", endian_buf[i]);
5628 				  *ptr++ = byte[0];
5629 				  *ptr++ = byte[1];
5630 			      }
5631 			}
5632 		  }
5633 	    }
5634 	  polyg = polyg->Next;
5635       }
5636 
5637 /* terminating the EWKB string */
5638     *ptr = '\0';
5639     gaiaAppendToOutBuffer (out_buf, buf);
5640 }
5641 
5642 static int
coordDimsFromFgf(int endian_arch,const unsigned char * blob,unsigned int size,int * type)5643 coordDimsFromFgf (int endian_arch, const unsigned char *blob, unsigned int size,
5644 		  int *type)
5645 {
5646 /* decoding the coordinate Dimensions for an FGF Geometry */
5647     int coord_dims;
5648     if (size < 4)
5649 	return 0;
5650     coord_dims = gaiaImport32 (blob, GAIA_LITTLE_ENDIAN, endian_arch);
5651     *type = coord_dims;
5652     switch (coord_dims)
5653       {
5654       case GAIA_XY:
5655 	  return 2;
5656       case GAIA_XY_M:
5657       case GAIA_XY_Z:
5658 	  return 3;
5659       case GAIA_XY_Z_M:
5660 	  return 4;
5661       default:
5662 	  return 0;
5663       }
5664 }
5665 
5666 static int
pointFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size,unsigned int * consumed)5667 pointFromFgf (gaiaGeomCollPtr geom, int endian_arch, const unsigned char *blob,
5668 	      unsigned int size, unsigned int *consumed)
5669 {
5670 /* decoding a POINT Geometry from FGF  */
5671     double x;
5672     double y;
5673     double z;
5674     double m;
5675     unsigned int sz = size;
5676     const unsigned char *ptr = blob;
5677     int coord_dims;
5678     int type;
5679 /* checking Geometry Type */
5680     if (sz < 4)
5681 	return 0;
5682     if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_POINT)
5683 	return 0;
5684     ptr += 4;
5685     sz -= 4;
5686 /* checking size */
5687     if (sz < 4)
5688 	return 0;
5689     coord_dims = coordDimsFromFgf (endian_arch, ptr, size, &type);
5690     if (!coord_dims)
5691 	return 0;
5692     ptr += 4;
5693     sz -= 4;
5694     if (sz < (coord_dims * sizeof (double)))
5695 	return 0;
5696     if (consumed)
5697 	*consumed = coord_dims * sizeof (double);
5698     if (type == GAIA_XY_Z)
5699       {
5700 	  /* building the POINTZ */
5701 	  x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5702 	  y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5703 	  z = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5704 	  gaiaAddPointToGeomCollXYZ (geom, x, y, z);
5705       }
5706     else if (type == GAIA_XY_M)
5707       {
5708 	  /* building the POINTM */
5709 	  x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5710 	  y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5711 	  m = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5712 	  gaiaAddPointToGeomCollXYM (geom, x, y, m);
5713       }
5714     else if (type == GAIA_XY_Z_M)
5715       {
5716 	  /* building the POINTZM */
5717 	  x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5718 	  y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5719 	  z = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5720 	  m = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5721 	  gaiaAddPointToGeomCollXYZM (geom, x, y, z, m);
5722       }
5723     else
5724       {
5725 	  /* building the POINT */
5726 	  x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5727 	  y = gaiaImport64 (ptr + 8, GAIA_LITTLE_ENDIAN, endian_arch);
5728 	  gaiaAddPointToGeomColl (geom, x, y);
5729       }
5730     return 1;
5731 }
5732 
5733 static int
linestringFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size,unsigned int * consumed)5734 linestringFromFgf (gaiaGeomCollPtr geom, int endian_arch,
5735 		   const unsigned char *blob, unsigned int size,
5736 		   unsigned int *consumed)
5737 {
5738 /* decoding a LINESTRING Geometry from FGF  */
5739     gaiaLinestringPtr ln;
5740     int pts;
5741     int iv;
5742     double x;
5743     double y;
5744     unsigned int ln_sz;
5745     unsigned int sz = size;
5746     const unsigned char *ptr = blob;
5747     int coord_dims;
5748     int type;
5749 /* checking Geometry Type */
5750     if (sz < 4)
5751 	return 0;
5752     if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_LINESTRING)
5753 	return 0;
5754     ptr += 4;
5755     sz -= 4;
5756 /* checking size */
5757     coord_dims = coordDimsFromFgf (endian_arch, ptr, size, &type);
5758     if (!coord_dims)
5759 	return 0;
5760     ptr += 4;
5761     sz -= 4;
5762 /* how many points are there ? */
5763     if (sz < 4)
5764 	return 0;
5765     pts = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5766     ptr += 4;
5767     sz -= 4;
5768     if (pts < 2)
5769 	return 0;
5770     ln_sz = pts * coord_dims * sizeof (double);
5771     if (sz < ln_sz)
5772 	return 0;
5773     if (consumed)
5774 	*consumed = (12 + ln_sz);
5775     if (type == GAIA_XY_Z)
5776       {
5777 	  /* building the LINESTRINGZ */
5778 	  geom->DimensionModel = GAIA_XY_Z;
5779 	  ln = gaiaAddLinestringToGeomColl (geom, pts);
5780 	  for (iv = 0; iv < pts; iv++)
5781 	    {
5782 		/* inserting vertices into the linestring */
5783 		x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5784 		y = gaiaImport64 (ptr + sizeof (double), GAIA_LITTLE_ENDIAN,
5785 				  endian_arch);
5786 		ptr += (coord_dims * sizeof (double));
5787 		gaiaSetPoint (ln->Coords, iv, x, y);
5788 	    }
5789       }
5790     else if (type == GAIA_XY_M)
5791       {
5792 	  /* building the LINESTRINGM */
5793 	  geom->DimensionModel = GAIA_XY_M;
5794 	  ln = gaiaAddLinestringToGeomColl (geom, pts);
5795 	  for (iv = 0; iv < pts; iv++)
5796 	    {
5797 		/* inserting vertices into the linestring */
5798 		x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5799 		y = gaiaImport64 (ptr + sizeof (double), GAIA_LITTLE_ENDIAN,
5800 				  endian_arch);
5801 		ptr += (coord_dims * sizeof (double));
5802 		gaiaSetPoint (ln->Coords, iv, x, y);
5803 	    }
5804       }
5805     else if (type == GAIA_XY_Z_M)
5806       {
5807 	  /* building the LINESTRINGZM */
5808 	  geom->DimensionModel = GAIA_XY_Z_M;
5809 	  ln = gaiaAddLinestringToGeomColl (geom, pts);
5810 	  for (iv = 0; iv < pts; iv++)
5811 	    {
5812 		/* inserting vertices into the linestring */
5813 		x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5814 		y = gaiaImport64 (ptr + sizeof (double), GAIA_LITTLE_ENDIAN,
5815 				  endian_arch);
5816 		ptr += (coord_dims * sizeof (double));
5817 		gaiaSetPoint (ln->Coords, iv, x, y);
5818 	    }
5819       }
5820     else
5821       {
5822 	  /* building the LINESTRING */
5823 	  geom->DimensionModel = GAIA_XY;
5824 	  ln = gaiaAddLinestringToGeomColl (geom, pts);
5825 	  for (iv = 0; iv < pts; iv++)
5826 	    {
5827 		/* inserting vertices into the linestring */
5828 		x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5829 		y = gaiaImport64 (ptr + sizeof (double), GAIA_LITTLE_ENDIAN,
5830 				  endian_arch);
5831 		ptr += (coord_dims * sizeof (double));
5832 		gaiaSetPoint (ln->Coords, iv, x, y);
5833 	    }
5834       }
5835     return 1;
5836 }
5837 
5838 static int
polygonFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size,unsigned int * consumed)5839 polygonFromFgf (gaiaGeomCollPtr geom, int endian_arch,
5840 		const unsigned char *blob, unsigned int size,
5841 		unsigned int *consumed)
5842 {
5843 /* decoding a POLYGON Geometry from FGF  */
5844     gaiaPolygonPtr pg = NULL;
5845     gaiaRingPtr rng;
5846     int rings;
5847     int ir;
5848     int pts;
5849     int iv;
5850     double x;
5851     double y;
5852     double z;
5853     double m;
5854     unsigned int rng_sz;
5855     unsigned int sz = size;
5856     const unsigned char *ptr = blob;
5857     int coord_dims;
5858     int type;
5859     unsigned int bytes = 0;
5860 /* checking Geometry Type */
5861     if (sz < 4)
5862 	return 0;
5863     if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_POLYGON)
5864 	return 0;
5865     ptr += 4;
5866     sz -= 4;
5867     bytes += 4;
5868 /* checking size */
5869     coord_dims = coordDimsFromFgf (endian_arch, ptr, size, &type);
5870     if (!coord_dims)
5871 	return 0;
5872     ptr += 4;
5873     sz -= 4;
5874     bytes += 4;
5875 /* how many rings are there ? */
5876     if (sz < 4)
5877 	return 0;
5878     rings = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5879     ptr += 4;
5880     sz -= 4;
5881     bytes += 4;
5882     if (rings < 1)
5883 	return 0;
5884     for (ir = 0; ir < rings; ir++)
5885       {
5886 	  /* fetching Polygon's rings */
5887 	  if (sz < 4)
5888 	      return 0;
5889 	  pts = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
5890 	  ptr += 4;
5891 	  sz -= 4;
5892 	  bytes += 4;
5893 	  if (pts < 4)
5894 	      return 0;
5895 	  rng_sz = pts * coord_dims * sizeof (double);
5896 	  if (sz < rng_sz)
5897 	      return 0;
5898 	  bytes += rng_sz;
5899 	  if (type == GAIA_XY_Z)
5900 	    {
5901 		/* POLYGONZ */
5902 		geom->DimensionModel = GAIA_XY_Z;
5903 		if (ir == 0)
5904 		  {
5905 		      /* building the EXTERIOR RING */
5906 		      pg = gaiaAddPolygonToGeomColl (geom, pts, rings - 1);
5907 		      rng = pg->Exterior;
5908 		      for (iv = 0; iv < pts; iv++)
5909 			{
5910 			    /* inserting vertices into the EXTERIOR Ring */
5911 			    x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5912 					      endian_arch);
5913 			    y = gaiaImport64 (ptr + sizeof (double),
5914 					      GAIA_LITTLE_ENDIAN, endian_arch);
5915 			    z = gaiaImport64 (ptr + (sizeof (double) * 2),
5916 					      GAIA_LITTLE_ENDIAN, endian_arch);
5917 			    ptr += (coord_dims * sizeof (double));
5918 			    gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
5919 			}
5920 		  }
5921 		else
5922 		  {
5923 		      /* building an INTERIOR RING */
5924 		      rng = gaiaAddInteriorRing (pg, ir - 1, pts);
5925 		      for (iv = 0; iv < pts; iv++)
5926 			{
5927 			    /* inserting vertices into some INTERIOR Ring */
5928 			    x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5929 					      endian_arch);
5930 			    y = gaiaImport64 (ptr + sizeof (double),
5931 					      GAIA_LITTLE_ENDIAN, endian_arch);
5932 			    z = gaiaImport64 (ptr + (sizeof (double) * 2),
5933 					      GAIA_LITTLE_ENDIAN, endian_arch);
5934 			    ptr += (coord_dims * sizeof (double));
5935 			    gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
5936 			}
5937 		  }
5938 	    }
5939 	  if (type == GAIA_XY_M)
5940 	    {
5941 		/* POLYGONM */
5942 		geom->DimensionModel = GAIA_XY_M;
5943 		if (ir == 0)
5944 		  {
5945 		      /* building the EXTERIOR RING */
5946 		      pg = gaiaAddPolygonToGeomColl (geom, pts, rings - 1);
5947 		      rng = pg->Exterior;
5948 		      for (iv = 0; iv < pts; iv++)
5949 			{
5950 			    /* inserting vertices into the EXTERIOR Ring */
5951 			    x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5952 					      endian_arch);
5953 			    y = gaiaImport64 (ptr + sizeof (double),
5954 					      GAIA_LITTLE_ENDIAN, endian_arch);
5955 			    m = gaiaImport64 (ptr + (sizeof (double) * 2),
5956 					      GAIA_LITTLE_ENDIAN, endian_arch);
5957 			    ptr += (coord_dims * sizeof (double));
5958 			    gaiaSetPointXYM (rng->Coords, iv, x, y, m);
5959 			}
5960 		  }
5961 		else
5962 		  {
5963 		      /* building an INTERIOR RING */
5964 		      rng = gaiaAddInteriorRing (pg, ir - 1, pts);
5965 		      for (iv = 0; iv < pts; iv++)
5966 			{
5967 			    /* inserting vertices into some INTERIOR Ring */
5968 			    x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5969 					      endian_arch);
5970 			    y = gaiaImport64 (ptr + sizeof (double),
5971 					      GAIA_LITTLE_ENDIAN, endian_arch);
5972 			    m = gaiaImport64 (ptr + (sizeof (double) * 2),
5973 					      GAIA_LITTLE_ENDIAN, endian_arch);
5974 			    ptr += (coord_dims * sizeof (double));
5975 			    gaiaSetPointXYM (rng->Coords, iv, x, y, m);
5976 			}
5977 		  }
5978 	    }
5979 	  else if (type == GAIA_XY_Z_M)
5980 	    {
5981 		/* POLYGONZM */
5982 		geom->DimensionModel = GAIA_XY_Z_M;
5983 		if (ir == 0)
5984 		  {
5985 		      /* building the EXTERIOR RING */
5986 		      pg = gaiaAddPolygonToGeomColl (geom, pts, rings - 1);
5987 		      rng = pg->Exterior;
5988 		      for (iv = 0; iv < pts; iv++)
5989 			{
5990 			    /* inserting vertices into the EXTERIOR Ring */
5991 			    x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
5992 					      endian_arch);
5993 			    y = gaiaImport64 (ptr + sizeof (double),
5994 					      GAIA_LITTLE_ENDIAN, endian_arch);
5995 			    z = gaiaImport64 (ptr + (sizeof (double) * 2),
5996 					      GAIA_LITTLE_ENDIAN, endian_arch);
5997 			    m = gaiaImport64 (ptr + (sizeof (double) * 3),
5998 					      GAIA_LITTLE_ENDIAN, endian_arch);
5999 			    ptr += (coord_dims * sizeof (double));
6000 			    gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
6001 			}
6002 		  }
6003 		else
6004 		  {
6005 		      /* building an INTERIOR RING */
6006 		      rng = gaiaAddInteriorRing (pg, ir - 1, pts);
6007 		      for (iv = 0; iv < pts; iv++)
6008 			{
6009 			    /* inserting vertices into some INTERIOR Ring */
6010 			    x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
6011 					      endian_arch);
6012 			    y = gaiaImport64 (ptr + sizeof (double),
6013 					      GAIA_LITTLE_ENDIAN, endian_arch);
6014 			    z = gaiaImport64 (ptr + (sizeof (double) * 2),
6015 					      GAIA_LITTLE_ENDIAN, endian_arch);
6016 			    m = gaiaImport64 (ptr + (sizeof (double) * 3),
6017 					      GAIA_LITTLE_ENDIAN, endian_arch);
6018 			    ptr += (coord_dims * sizeof (double));
6019 			    gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
6020 			}
6021 		  }
6022 	    }
6023 	  else
6024 	    {
6025 		/* POLYGON */
6026 		geom->DimensionModel = GAIA_XY;
6027 		if (ir == 0)
6028 		  {
6029 		      /* building the EXTERIOR RING */
6030 		      pg = gaiaAddPolygonToGeomColl (geom, pts, rings - 1);
6031 		      rng = pg->Exterior;
6032 		      for (iv = 0; iv < pts; iv++)
6033 			{
6034 			    /* inserting vertices into the EXTERIOR Ring */
6035 			    x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
6036 					      endian_arch);
6037 			    y = gaiaImport64 (ptr + sizeof (double),
6038 					      GAIA_LITTLE_ENDIAN, endian_arch);
6039 			    ptr += (coord_dims * sizeof (double));
6040 			    gaiaSetPoint (rng->Coords, iv, x, y);
6041 			}
6042 		  }
6043 		else
6044 		  {
6045 		      /* building an INTERIOR RING */
6046 		      rng = gaiaAddInteriorRing (pg, ir - 1, pts);
6047 		      for (iv = 0; iv < pts; iv++)
6048 			{
6049 			    /* inserting vertices into some INTERIOR Ring */
6050 			    x = gaiaImport64 (ptr, GAIA_LITTLE_ENDIAN,
6051 					      endian_arch);
6052 			    y = gaiaImport64 (ptr + sizeof (double),
6053 					      GAIA_LITTLE_ENDIAN, endian_arch);
6054 			    ptr += (coord_dims * sizeof (double));
6055 			    gaiaSetPoint (rng->Coords, iv, x, y);
6056 			}
6057 		  }
6058 	    }
6059 	  sz -= rng_sz;
6060       }
6061     if (consumed)
6062 	*consumed = bytes;
6063     return 1;
6064 }
6065 
6066 static int
multiPointFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size)6067 multiPointFromFgf (gaiaGeomCollPtr geom, int endian_arch,
6068 		   const unsigned char *blob, unsigned int size)
6069 {
6070 /* decoding a MULTIPOINT Geometry from FGF  */
6071     int pts;
6072     int ipt;
6073     unsigned int sz = size;
6074     const unsigned char *ptr = blob;
6075     unsigned int consumed;
6076 /* checking Geometry Type */
6077     if (sz < 4)
6078 	return 0;
6079     if (gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_MULTIPOINT)
6080 	return 0;
6081     ptr += 4;
6082     sz -= 4;
6083 /* how many points are there ? */
6084     if (sz < 4)
6085 	return 0;
6086     pts = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6087     ptr += 4;
6088     sz -= 4;
6089     if (pts < 1)
6090 	return 0;
6091     for (ipt = 0; ipt < pts; ipt++)
6092       {
6093 	  /* fetching individual Points from FGF */
6094 	  if (!pointFromFgf (geom, endian_arch, ptr, sz, &consumed))
6095 	      return 0;
6096 	  ptr += consumed;
6097 	  sz -= consumed;
6098       }
6099     return 1;
6100 }
6101 
6102 static int
multiLinestringFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size)6103 multiLinestringFromFgf (gaiaGeomCollPtr geom, int endian_arch,
6104 			const unsigned char *blob, unsigned int size)
6105 {
6106 /* decoding a MULTILINESTRING Geometry from FGF  */
6107     int lns;
6108     int iln;
6109     unsigned int sz = size;
6110     const unsigned char *ptr = blob;
6111     unsigned int consumed;
6112 /* checking Geometry Type */
6113     if (sz < 4)
6114 	return 0;
6115     if (gaiaImport32
6116 	(ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_MULTILINESTRING)
6117 	return 0;
6118     ptr += 4;
6119     sz -= 4;
6120 /* how many linestrings are there ? */
6121     if (sz < 4)
6122 	return 0;
6123     lns = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6124     ptr += 4;
6125     sz -= 4;
6126     if (lns < 1)
6127 	return 0;
6128     for (iln = 0; iln < lns; iln++)
6129       {
6130 	  /* fetching individual Linestrings from FGF */
6131 	  if (!linestringFromFgf (geom, endian_arch, ptr, sz, &consumed))
6132 	      return 0;
6133 	  ptr += consumed;
6134 	  sz -= consumed;
6135       }
6136     return 1;
6137 }
6138 
6139 static int
multiPolygonFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size)6140 multiPolygonFromFgf (gaiaGeomCollPtr geom, int endian_arch,
6141 		     const unsigned char *blob, unsigned int size)
6142 {
6143 /* decoding a MULTIPOLYGON Geometry from FGF  */
6144     int pgs;
6145     int ipg;
6146     unsigned int sz = size;
6147     const unsigned char *ptr = blob;
6148     unsigned int consumed;
6149 /* checking Geometry Type */
6150     if (sz < 4)
6151 	return 0;
6152     if (gaiaImport32
6153 	(ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_MULTIPOLYGON)
6154 	return 0;
6155     ptr += 4;
6156     sz -= 4;
6157 /* how many polygons are there ? */
6158     if (sz < 4)
6159 	return 0;
6160     pgs = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6161     ptr += 4;
6162     sz -= 4;
6163     if (pgs < 1)
6164 	return 0;
6165     for (ipg = 0; ipg < pgs; ipg++)
6166       {
6167 	  /* fetching individual Polygons from FGF */
6168 	  if (!polygonFromFgf (geom, endian_arch, ptr, sz, &consumed))
6169 	      return 0;
6170 	  ptr += consumed;
6171 	  sz -= consumed;
6172       }
6173     return 1;
6174 }
6175 
6176 static int
geomCollectionFromFgf(gaiaGeomCollPtr geom,int endian_arch,const unsigned char * blob,unsigned int size)6177 geomCollectionFromFgf (gaiaGeomCollPtr geom, int endian_arch,
6178 		       const unsigned char *blob, unsigned int size)
6179 {
6180 /* decoding a  GEOMETRYCOLLECTION Geometry from FGF  */
6181     int geoms;
6182     int ig;
6183     int geom_type;
6184     unsigned int sz = size;
6185     const unsigned char *ptr = blob;
6186     unsigned int consumed;
6187 /* checking Geometry Type */
6188     if (sz < 4)
6189 	return 0;
6190     if (gaiaImport32
6191 	(ptr, GAIA_LITTLE_ENDIAN, endian_arch) != GAIA_GEOMETRYCOLLECTION)
6192 	return 0;
6193     ptr += 4;
6194     sz -= 4;
6195 /* how many individual Geometries are there ? */
6196     if (sz < 4)
6197 	return 0;
6198     geoms = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6199     ptr += 4;
6200     sz -= 4;
6201     if (geoms < 1)
6202 	return 0;
6203     for (ig = 0; ig < geoms; ig++)
6204       {
6205 	  /* fetching individual Geometries from FGF */
6206 	  if (sz < 4)
6207 	      return 0;
6208 	  geom_type = gaiaImport32 (ptr, GAIA_LITTLE_ENDIAN, endian_arch);
6209 	  switch (geom_type)
6210 	    {
6211 	    case GAIA_POINT:
6212 		if (!pointFromFgf (geom, endian_arch, ptr, sz, &consumed))
6213 		    return 0;
6214 		break;
6215 	    case GAIA_LINESTRING:
6216 		if (!linestringFromFgf (geom, endian_arch, ptr, sz, &consumed))
6217 		    return 0;
6218 		break;
6219 	    case GAIA_POLYGON:
6220 		if (!polygonFromFgf (geom, endian_arch, ptr, sz, &consumed))
6221 		    return 0;
6222 		break;
6223 	    default:		/* unsupported geometry type */
6224 		return 0;
6225 		break;
6226 	    };
6227 	  ptr += consumed;
6228 	  sz -= consumed;
6229       }
6230     return 1;
6231 }
6232 
6233 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromFgf(const unsigned char * blob,unsigned int size)6234 gaiaFromFgf (const unsigned char *blob, unsigned int size)
6235 {
6236 /* decoding from FGF to GEOMETRY  */
6237     gaiaGeomCollPtr geom = NULL;
6238     int geom_type;
6239     int endian_arch = gaiaEndianArch ();
6240     if (size < 4)
6241 	return NULL;
6242 /* checking FGF type */
6243     geom_type = gaiaImport32 (blob, GAIA_LITTLE_ENDIAN, endian_arch);
6244     geom = gaiaAllocGeomColl ();
6245     geom->DeclaredType = geom_type;
6246     switch (geom_type)
6247       {
6248       case GAIA_POINT:
6249 	  if (pointFromFgf (geom, endian_arch, blob, size, NULL))
6250 	      return geom;
6251 	  break;
6252       case GAIA_LINESTRING:
6253 	  if (linestringFromFgf (geom, endian_arch, blob, size, NULL))
6254 	      return geom;
6255 	  break;
6256       case GAIA_POLYGON:
6257 	  if (polygonFromFgf (geom, endian_arch, blob, size, NULL))
6258 	      return geom;
6259 	  break;
6260       case GAIA_MULTIPOINT:
6261 	  if (multiPointFromFgf (geom, endian_arch, blob, size))
6262 	      return geom;
6263 	  break;
6264       case GAIA_MULTILINESTRING:
6265 	  if (multiLinestringFromFgf (geom, endian_arch, blob, size))
6266 	      return geom;
6267 	  break;
6268       case GAIA_MULTIPOLYGON:
6269 	  if (multiPolygonFromFgf (geom, endian_arch, blob, size))
6270 	      return geom;
6271 	  break;
6272       case GAIA_GEOMETRYCOLLECTION:
6273 	  if (geomCollectionFromFgf (geom, endian_arch, blob, size))
6274 	      return geom;
6275 	  break;
6276       default:			/* unsupported geometry type */
6277 	  break;
6278       };
6279     gaiaFreeGeomColl (geom);
6280     return NULL;
6281 }
6282 
6283 GAIAGEO_DECLARE void
gaiaToFgf(gaiaGeomCollPtr geom,unsigned char ** result,int * size,int coord_dims)6284 gaiaToFgf (gaiaGeomCollPtr geom, unsigned char **result, int *size,
6285 	   int coord_dims)
6286 {
6287 /* builds the FGF representation for this GEOMETRY */
6288     int ib;
6289     int iv;
6290     double x;
6291     double y;
6292     double z;
6293     double m;
6294     int entities = 0;
6295     int n_points = 0;
6296     int n_linestrings = 0;
6297     int n_polygons = 0;
6298     int type;
6299     int n_coords;
6300     unsigned char *ptr;
6301     int sz = 0;
6302     gaiaPointPtr pt;
6303     gaiaLinestringPtr ln;
6304     gaiaPolygonPtr pg;
6305     gaiaRingPtr rng;
6306     gaiaPointPtr point = NULL;
6307     gaiaLinestringPtr line = NULL;
6308     gaiaPolygonPtr polyg = NULL;
6309     int endian_arch = gaiaEndianArch ();
6310     gaiaMbrGeometry (geom);
6311     switch (coord_dims)
6312       {
6313       case GAIA_XY:
6314 	  n_coords = 2;
6315 	  break;
6316       case GAIA_XY_M:
6317       case GAIA_XY_Z:
6318 	  n_coords = 3;
6319 	  break;
6320       case GAIA_XY_Z_M:
6321 	  n_coords = 4;
6322 	  break;
6323       default:
6324 	  n_coords = 0;
6325 	  break;
6326       }
6327 /* how many entities, and of what kind, do we have ? */
6328     pt = geom->FirstPoint;
6329     while (pt)
6330       {
6331 	  point = pt;
6332 	  entities++;
6333 	  n_points++;
6334 	  pt = pt->Next;
6335       }
6336     ln = geom->FirstLinestring;
6337     while (ln)
6338       {
6339 	  line = ln;
6340 	  entities++;
6341 	  n_linestrings++;
6342 	  ln = ln->Next;
6343       }
6344     pg = geom->FirstPolygon;
6345     while (pg)
6346       {
6347 	  polyg = pg;
6348 	  entities++;
6349 	  n_polygons++;
6350 	  pg = pg->Next;
6351       }
6352     *size = 0;
6353     sz = 0;
6354     *result = NULL;
6355     if (n_points == 0 && n_polygons == 0 && n_linestrings == 0)
6356 	return;
6357 /* ok, we can determine the geometry class */
6358     if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
6359       {
6360 	  if (geom->DeclaredType == GAIA_MULTIPOINT)
6361 	      type = GAIA_MULTIPOINT;
6362 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6363 	      type = GAIA_GEOMETRYCOLLECTION;
6364 	  else
6365 	      type = GAIA_POINT;
6366       }
6367     else if (n_points > 1 && n_linestrings == 0 && n_polygons == 0)
6368       {
6369 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6370 	      type = GAIA_GEOMETRYCOLLECTION;
6371 	  else
6372 	      type = GAIA_MULTIPOINT;
6373       }
6374     else if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
6375       {
6376 	  if (geom->DeclaredType == GAIA_MULTILINESTRING)
6377 	      type = GAIA_MULTILINESTRING;
6378 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6379 	      type = GAIA_GEOMETRYCOLLECTION;
6380 	  else
6381 	      type = GAIA_LINESTRING;
6382       }
6383     else if (n_points == 0 && n_linestrings > 1 && n_polygons == 0)
6384       {
6385 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6386 	      type = GAIA_GEOMETRYCOLLECTION;
6387 	  else
6388 	      type = GAIA_MULTILINESTRING;
6389       }
6390     else if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
6391       {
6392 	  if (geom->DeclaredType == GAIA_MULTIPOLYGON)
6393 	      type = GAIA_MULTIPOLYGON;
6394 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6395 	      type = GAIA_GEOMETRYCOLLECTION;
6396 	  else
6397 	      type = GAIA_POLYGON;
6398       }
6399     else if (n_points == 0 && n_linestrings == 0 && n_polygons > 1)
6400       {
6401 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
6402 	      type = GAIA_GEOMETRYCOLLECTION;
6403 	  else
6404 	      type = GAIA_MULTIPOLYGON;
6405       }
6406     else
6407 	type = GAIA_GEOMETRYCOLLECTION;
6408 /* and now we compute the size of FGF */
6409     if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
6410 	|| type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
6411 	sz += 8;
6412     point = geom->FirstPoint;
6413     while (point)
6414       {
6415 	  sz += (8 + (n_coords * sizeof (double)));	/* the size of each POINT */
6416 	  point = point->Next;
6417       }
6418     line = geom->FirstLinestring;
6419     while (line)
6420       {
6421 	  sz += (12 + ((n_coords * sizeof (double)) * line->Points));	/* # points + [x,y] for each vertex */
6422 	  line = line->Next;
6423       }
6424     polyg = geom->FirstPolygon;
6425     while (polyg)
6426       {
6427 	  rng = polyg->Exterior;
6428 	  sz += (16 + ((n_coords * sizeof (double)) * rng->Points));	/* # rings + # points + [x.y] array - exterior ring */
6429 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
6430 	    {
6431 		rng = polyg->Interiors + ib;
6432 		sz += (4 + ((n_coords * sizeof (double)) * rng->Points));	/* # points + [x,y] array - interior ring */
6433 	    }
6434 	  polyg = polyg->Next;
6435       }
6436     *size = sz;
6437     ptr = malloc (sz);
6438     *result = ptr;
6439 /* and finally we build the FGF */
6440     if (type == GAIA_MULTIPOINT || type == GAIA_MULTILINESTRING
6441 	|| type == GAIA_MULTIPOLYGON || type == GAIA_GEOMETRYCOLLECTION)
6442       {
6443 	  gaiaExport32 (ptr, type, GAIA_LITTLE_ENDIAN, endian_arch);	/* Geometry Type */
6444 	  ptr += 4;
6445 	  gaiaExport32 (ptr, entities, GAIA_LITTLE_ENDIAN, endian_arch);	/* it's a collection; # entities */
6446 	  ptr += 4;
6447       }
6448     point = geom->FirstPoint;
6449     while (point)
6450       {
6451 	  gaiaExport32 (ptr, GAIA_POINT, GAIA_LITTLE_ENDIAN, endian_arch);	/* the CLASS TYPE for this element */
6452 	  ptr += 4;
6453 	  gaiaExport32 (ptr, coord_dims, GAIA_LITTLE_ENDIAN, endian_arch);	/* the CoordDimension */
6454 	  ptr += 4;
6455 	  gaiaExport64 (ptr, point->X, GAIA_LITTLE_ENDIAN, endian_arch);	/* X */
6456 	  ptr += 8;
6457 	  gaiaExport64 (ptr, point->Y, GAIA_LITTLE_ENDIAN, endian_arch);	/* Y */
6458 	  ptr += 8;
6459 	  if (n_coords > 2)
6460 	    {
6461 		/* the third coordinate [Z or M] */
6462 		if (coord_dims == GAIA_XY_Z || coord_dims == GAIA_XY_Z_M)
6463 		    gaiaExport64 (ptr, point->Z, GAIA_LITTLE_ENDIAN,
6464 				  endian_arch);
6465 		else
6466 		    gaiaExport64 (ptr, point->M, GAIA_LITTLE_ENDIAN,
6467 				  endian_arch);
6468 		ptr += 8;
6469 	    }
6470 	  if (n_coords > 3)
6471 	    {
6472 		/* the fourth coordinate [M] */
6473 		gaiaExport64 (ptr, point->M, GAIA_LITTLE_ENDIAN, endian_arch);
6474 		ptr += 8;
6475 	    }
6476 	  point = point->Next;
6477       }
6478     line = geom->FirstLinestring;
6479     while (line)
6480       {
6481 	  gaiaExport32 (ptr, GAIA_LINESTRING, GAIA_LITTLE_ENDIAN, endian_arch);	/* the CLASS TYPE for this element */
6482 	  ptr += 4;
6483 	  gaiaExport32 (ptr, coord_dims, GAIA_LITTLE_ENDIAN, endian_arch);	/* the CoordDimension */
6484 	  ptr += 4;
6485 	  gaiaExport32 (ptr, line->Points, GAIA_LITTLE_ENDIAN, endian_arch);	/* # points */
6486 	  ptr += 4;
6487 	  for (iv = 0; iv < line->Points; iv++)
6488 	    {
6489 		z = 0.0;
6490 		m = 0.0;
6491 		if (geom->DimensionModel == GAIA_XY_Z)
6492 		  {
6493 		      gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
6494 		  }
6495 		else if (geom->DimensionModel == GAIA_XY_M)
6496 		  {
6497 		      gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
6498 		  }
6499 		else if (geom->DimensionModel == GAIA_XY_Z_M)
6500 		  {
6501 		      gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
6502 		  }
6503 		else
6504 		  {
6505 		      gaiaGetPoint (line->Coords, iv, &x, &y);
6506 		  }
6507 		gaiaExport64 (ptr, x, GAIA_LITTLE_ENDIAN, endian_arch);	/* X */
6508 		ptr += 8;
6509 		gaiaExport64 (ptr, y, GAIA_LITTLE_ENDIAN, endian_arch);	/* Y */
6510 		ptr += 8;
6511 		if (n_coords > 2)
6512 		  {
6513 		      /* the third coordinate [Z or M] */
6514 		      if (coord_dims == GAIA_XY_Z || coord_dims == GAIA_XY_Z_M)
6515 			  gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN,
6516 					endian_arch);
6517 		      else
6518 			  gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN,
6519 					endian_arch);
6520 		      ptr += 8;
6521 		  }
6522 		if (n_coords > 3)
6523 		  {
6524 		      /* the fourth coordinate [M]; */
6525 		      gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch);
6526 		      ptr += 8;
6527 		  }
6528 	    }
6529 	  line = line->Next;
6530       }
6531     polyg = geom->FirstPolygon;
6532     while (polyg)
6533       {
6534 	  gaiaExport32 (ptr, GAIA_POLYGON, GAIA_LITTLE_ENDIAN, endian_arch);	/* the CLASS TYPE for this element */
6535 	  ptr += 4;
6536 	  gaiaExport32 (ptr, coord_dims, GAIA_LITTLE_ENDIAN, endian_arch);	/* the CoordDimension */
6537 	  ptr += 4;
6538 	  gaiaExport32 (ptr, polyg->NumInteriors + 1, GAIA_LITTLE_ENDIAN, endian_arch);	/* # rings */
6539 	  ptr += 4;
6540 	  rng = polyg->Exterior;
6541 	  gaiaExport32 (ptr, rng->Points, GAIA_LITTLE_ENDIAN, endian_arch);	/* # points - exterior ring */
6542 	  ptr += 4;
6543 	  for (iv = 0; iv < rng->Points; iv++)
6544 	    {
6545 		z = 0.0;
6546 		m = 0.0;
6547 		if (geom->DimensionModel == GAIA_XY_Z)
6548 		  {
6549 		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
6550 		  }
6551 		else if (geom->DimensionModel == GAIA_XY_M)
6552 		  {
6553 		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
6554 		  }
6555 		else if (geom->DimensionModel == GAIA_XY_Z_M)
6556 		  {
6557 		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
6558 		  }
6559 		else
6560 		  {
6561 		      gaiaGetPoint (rng->Coords, iv, &x, &y);
6562 		  }
6563 		gaiaExport64 (ptr, x, GAIA_LITTLE_ENDIAN, endian_arch);	/* X - exterior ring */
6564 		ptr += 8;
6565 		gaiaExport64 (ptr, y, GAIA_LITTLE_ENDIAN, endian_arch);	/* Y - exterior ring */
6566 		ptr += 8;
6567 		if (n_coords > 2)
6568 		  {
6569 		      /* the third coordinate [Z or M] */
6570 		      if (coord_dims == GAIA_XY_Z || coord_dims == GAIA_XY_Z_M)
6571 			  gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN,
6572 					endian_arch);
6573 		      else
6574 			  gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN,
6575 					endian_arch);
6576 		      ptr += 8;
6577 		  }
6578 		if (n_coords > 3)
6579 		  {
6580 		      /* the fourth coordinate [M] */
6581 		      gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN, endian_arch);
6582 		      ptr += 8;
6583 		  }
6584 	    }
6585 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
6586 	    {
6587 		rng = polyg->Interiors + ib;
6588 		gaiaExport32 (ptr, rng->Points, 1, endian_arch);	/* # points - interior ring */
6589 		ptr += 4;
6590 		for (iv = 0; iv < rng->Points; iv++)
6591 		  {
6592 		      z = 0.0;
6593 		      m = 0.0;
6594 		      if (geom->DimensionModel == GAIA_XY_Z)
6595 			{
6596 			    gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
6597 			}
6598 		      else if (geom->DimensionModel == GAIA_XY_M)
6599 			{
6600 			    gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
6601 			}
6602 		      else if (geom->DimensionModel == GAIA_XY_Z_M)
6603 			{
6604 			    gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
6605 			}
6606 		      else
6607 			{
6608 			    gaiaGetPoint (rng->Coords, iv, &x, &y);
6609 			}
6610 		      gaiaExport64 (ptr, x, GAIA_LITTLE_ENDIAN, endian_arch);	/* X - interior ring */
6611 		      ptr += 8;
6612 		      gaiaExport64 (ptr, y, GAIA_LITTLE_ENDIAN, endian_arch);	/* Y - interior ring */
6613 		      ptr += 8;
6614 		      if (n_coords > 2)
6615 			{
6616 			    /* the third coordinate [Z or M]; defaulting to ZERO */
6617 			    if (coord_dims == GAIA_XY_Z
6618 				|| coord_dims == GAIA_XY_Z_M)
6619 				gaiaExport64 (ptr, z, GAIA_LITTLE_ENDIAN,
6620 					      endian_arch);
6621 			    else
6622 				gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN,
6623 					      endian_arch);
6624 			    ptr += 8;
6625 			}
6626 		      if (n_coords > 3)
6627 			{
6628 			    /* the fourth coordinate [M] */
6629 			    gaiaExport64 (ptr, m, GAIA_LITTLE_ENDIAN,
6630 					  endian_arch);
6631 			    ptr += 8;
6632 			}
6633 		  }
6634 	    }
6635 	  polyg = polyg->Next;
6636       }
6637 }
6638