1 /*
2 
3  rl2wms -- WMS related functions
4 
5  version 0.1, 2013 July 28
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 RasterLite2 library
24 
25 The Initial Developer of the Original Code is Alessandro Furieri
26 
27 Portions created by the Initial Developer are Copyright (C) 2013
28 the Initial Developer. All Rights Reserved.
29 
30 Alternatively, the contents of this file may be used under the terms of
31 either the GNU General Public License Version 2 or later (the "GPL"), or
32 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 in which case the provisions of the GPL or the LGPL are applicable instead
34 of those above. If you wish to allow use of your version of this file only
35 under the terms of either the GPL or the LGPL, and not to allow others to
36 use your version of this file under the terms of the MPL, indicate your
37 decision by deleting the provisions above and replace them with the notice
38 and other provisions required by the GPL or the LGPL. If you do not delete
39 the provisions above, a recipient may use your version of this file under
40 the terms of any one of the MPL, the GPL or the LGPL.
41 
42 */
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <float.h>
46 #include <math.h>
47 #include <string.h>
48 #include <time.h>
49 
50 #include <curl/curl.h>
51 #include <libxml/parser.h>
52 
53 #include "rasterlite2/sqlite.h"
54 
55 #include "rasterlite2/rasterlite2.h"
56 #include "rasterlite2/rl2wms.h"
57 
58 #define WMS_FORMAT_UNKNOWN	0
59 #define WMS_FORMAT_GIF		1
60 #define WMS_FORMAT_PNG		2
61 #define WMS_FORMAT_PNG8		3
62 #define WMS_FORMAT_PNG24	4
63 #define WMS_FORMAT_PNG32	5
64 #define WMS_FORMAT_JPEG		6
65 #define WMS_FORMAT_TIFF		7
66 
67 typedef struct wmsMemBufferStruct
68 {
69 /* a struct handling a dynamically growing output buffer */
70     unsigned char *Buffer;
71     size_t WriteOffset;
72     size_t BufferSize;
73     int Error;
74 } wmsMemBuffer;
75 typedef wmsMemBuffer *wmsMemBufferPtr;
76 
77 typedef struct wmsCachedCapabilitiesStruct
78 {
79 /* a WMS Cached GetCapabilities response */
80     char *Url;
81     unsigned char *Response;
82     struct wmsCachedCapabilitiesStruct *Next;
83 } wmsCachedCapabilities;
84 typedef wmsCachedCapabilities *wmsCachedCapabilitiesPtr;
85 
86 typedef struct wmsCachedItemStruct
87 {
88 /* a WMS Cached Item */
89     char *Url;
90     time_t Time;
91     int Size;
92     unsigned char *Item;
93     int ImageFormat;
94     struct wmsCachedItemStruct *Prev;
95     struct wmsCachedItemStruct *Next;
96 } wmsCachedItem;
97 typedef wmsCachedItem *wmsCachedItemPtr;
98 
99 typedef struct wmsCacheStruct
100 {
101 /* a struct implementing a WMS image cache */
102     int MaxSize;
103     int CurrentSize;
104     wmsCachedCapabilitiesPtr FirstCapab;
105     wmsCachedCapabilitiesPtr LastCapab;
106     wmsCachedItemPtr First;
107     wmsCachedItemPtr Last;
108     int NumCachedItems;
109     wmsCachedItemPtr *SortedByUrl;
110     wmsCachedItemPtr *SortedByTime;
111     int HitCount;
112     int MissCount;
113     int FlushedCount;
114     double TotalDownload;
115 } wmsCache;
116 typedef wmsCache *wmsCachePtr;
117 
118 typedef struct wmsFormatStruct
119 {
120 /* a struct wrapping a WMS Format */
121     int FormatCode;
122     char *Format;
123     struct wmsFormatStruct *next;
124 } wmsFormat;
125 typedef wmsFormat *wmsFormatPtr;
126 
127 typedef struct wmsCrsStruct
128 {
129 /* a struct wrapping a WMS CRS */
130     char *Crs;
131     struct wmsCrsStruct *next;
132 } wmsCrs;
133 typedef wmsCrs *wmsCrsPtr;
134 
135 typedef struct wmsBBoxStruct
136 {
137 /* a struct wrapping a WMS Bounding Box */
138     char *Crs;
139     double MinX;
140     double MaxX;
141     double MinY;
142     double MaxY;
143     struct wmsBBoxStruct *next;
144 } wmsBBox;
145 typedef wmsBBox *wmsBBoxPtr;
146 
147 typedef struct wmsStyleStruct
148 {
149 /* a struct wrapping a WMS Style */
150     char *Name;
151     char *Title;
152     char *Abstract;
153     struct wmsStyleStruct *next;
154 } wmsStyle;
155 typedef wmsStyle *wmsStylePtr;
156 
157 typedef struct wmsUrlArgumentStruct
158 {
159 /* struct wrapping a WMS URL argument */
160     char *argName;
161     char *argValue;
162     struct wmsUrlArgumentStruct *next;
163 } wmsUrlArgument;
164 typedef wmsUrlArgument *wmsUrlArgumentPtr;
165 
166 typedef struct wmsTilePatternStruct
167 {
168 /* struct wrapping a WMS TilePattern */
169     char *Pattern;
170     char *Format;
171     char *SRS;
172     char *Style;
173     int TileWidth;
174     int TileHeight;
175     double TileBaseX;
176     double TileBaseY;
177     double TileExtentX;
178     double TileExtentY;
179     wmsUrlArgumentPtr first;
180     wmsUrlArgumentPtr last;
181     struct wmsTilePatternStruct *next;
182 } wmsTilePattern;
183 typedef wmsTilePattern *wmsTilePatternPtr;
184 
185 typedef struct wmsTiledLayerStruct
186 {
187 /* a struct wrapping a WMS Tiled Layer */
188     char *Name;
189     char *Title;
190     char *Abstract;
191     double MinLat;
192     double MaxLat;
193     double MinLong;
194     double MaxLong;
195     char *Pad;
196     char *Bands;
197     char *DataType;
198     wmsTilePatternPtr firstPattern;
199     wmsTilePatternPtr lastPattern;
200     struct wmsTiledLayerStruct *firstChild;
201     struct wmsTiledLayerStruct *lastChild;
202     struct wmsTiledLayerStruct *next;
203 } wmsTiledLayer;
204 typedef wmsTiledLayer *wmsTiledLayerPtr;
205 
206 typedef struct wmsLayerStruct
207 {
208 /* a struct wrapping a WMS Layer */
209     int Queryable;
210     int Opaque;
211     char *Name;
212     char *Title;
213     char *Abstract;
214     double MinScaleDenominator;
215     double MaxScaleDenominator;
216     double MinLat;
217     double MaxLat;
218     double MinLong;
219     double MaxLong;
220     wmsBBoxPtr firstBBox;
221     wmsBBoxPtr lastBBox;
222     wmsCrsPtr firstCrs;
223     wmsCrsPtr lastCrs;
224     wmsStylePtr firstStyle;
225     wmsStylePtr lastStyle;
226     struct wmsLayerStruct *Parent;
227     struct wmsLayerStruct *firstLayer;
228     struct wmsLayerStruct *lastLayer;
229     struct wmsLayerStruct *next;
230 } wmsLayer;
231 typedef wmsLayer *wmsLayerPtr;
232 
233 typedef struct wmsCapabilitiesStruct
234 {
235 /* a struct wrapping a WMS Capabilities answer */
236     char *Version;
237     char *Name;
238     char *Title;
239     char *Abstract;
240     char *GetMapURLGet;
241     char *GetMapURLPost;
242     char *GetFeatureInfoURLGet;
243     char *GetFeatureInfoURLPost;
244     char *GetTileServiceURLGet;
245     char *GetTileServiceURLPost;
246     char *GmlMimeType;
247     char *XmlMimeType;
248     char *ContactPerson;
249     char *ContactOrganization;
250     char *ContactPosition;
251     char *PostalAddress;
252     char *City;
253     char *StateProvince;
254     char *PostCode;
255     char *Country;
256     char *VoiceTelephone;
257     char *FaxTelephone;
258     char *EMailAddress;
259     char *Fees;
260     char *AccessConstraints;
261     int LayerLimit;
262     int MaxWidth;
263     int MaxHeight;
264     wmsFormatPtr firstFormat;
265     wmsFormatPtr lastFormat;
266     wmsLayerPtr firstLayer;
267     wmsLayerPtr lastLayer;
268     char *TileServiceName;
269     char *TileServiceTitle;
270     char *TileServiceAbstract;
271     wmsTiledLayerPtr firstTiled;
272     wmsTiledLayerPtr lastTiled;
273 } wmsCapabilities;
274 typedef wmsCapabilities *wmsCapabilitiesPtr;
275 
276 typedef struct wmsFeatureAttributeStruct
277 {
278 /* a struct wrapping a GML FeatureAtrribute */
279     char *name;
280     char *value;
281     gaiaGeomCollPtr geometry;
282     struct wmsFeatureAttributeStruct *next;
283 } wmsFeatureAttribute;
284 typedef wmsFeatureAttribute *wmsFeatureAttributePtr;
285 
286 typedef struct wmsFeatureMemberStruct
287 {
288 /* a struct wrapping a GML FeatureMember */
289     char *layer_name;
290     wmsFeatureAttributePtr first;
291     wmsFeatureAttributePtr last;
292     struct wmsFeatureMemberStruct *next;
293 } wmsFeatureMember;
294 typedef wmsFeatureMember *wmsFeatureMemberPtr;
295 
296 typedef struct wmsFeatureCollectionStruct
297 {
298 /* a struct wrapping a WMS FeatureInfo answer */
299     wmsFeatureMemberPtr first;
300     wmsFeatureMemberPtr last;
301 } wmsFeatureCollection;
302 typedef wmsFeatureCollection *wmsFeatureCollectionPtr;
303 
304 typedef struct wmsSinglePartResponseStruct
305 {
306 /* a struct wrapping a single part body response */
307     char *body;
308     struct wmsSinglePartResponseStruct *next;
309 } wmsSinglePartResponse;
310 typedef wmsSinglePartResponse *wmsSinglePartResponsePtr;
311 
312 typedef struct wmsMultipartCollectionStruct
313 {
314 /* a struct wrapping a Multipart HTTP response */
315     wmsSinglePartResponse *first;
316     wmsSinglePartResponse *last;
317 } wmsMultipartCollection;
318 typedef wmsMultipartCollection *wmsMultipartCollectionPtr;
319 
320 static wmsCachedItemPtr
wmsAllocCachedItem(const char * url,const unsigned char * item,int size,const char * image_format)321 wmsAllocCachedItem (const char *url, const unsigned char *item, int size,
322 		    const char *image_format)
323 {
324 /* creating a WMS Cached Item */
325     int len;
326     time_t xtime;
327     wmsCachedItemPtr ptr = malloc (sizeof (wmsCachedItem));
328     len = strlen (url);
329     ptr->Url = malloc (len + 1);
330     strcpy (ptr->Url, url);
331     time (&xtime);
332     ptr->Time = xtime;
333     ptr->Size = size;
334     ptr->Item = malloc (size);
335     memcpy (ptr->Item, item, size);
336     ptr->ImageFormat = WMS_FORMAT_UNKNOWN;
337     if (strcmp (image_format, "image/gif") == 0)
338 	ptr->ImageFormat = WMS_FORMAT_GIF;
339     if (strcmp (image_format, "image/png") == 0)
340 	ptr->ImageFormat = WMS_FORMAT_PNG;
341     if (strcmp (image_format, "image/jpeg") == 0)
342 	ptr->ImageFormat = WMS_FORMAT_JPEG;
343     if (strcmp (image_format, "image/tiff") == 0)
344 	ptr->ImageFormat = WMS_FORMAT_TIFF;
345     ptr->Prev = NULL;
346     ptr->Next = NULL;
347     return ptr;
348 }
349 
350 static void
wmsFreeCachedItem(wmsCachedItemPtr ptr)351 wmsFreeCachedItem (wmsCachedItemPtr ptr)
352 {
353 /* memory cleanup - destroying a WMS Cached Item */
354     if (ptr == NULL)
355 	return;
356     if (ptr->Url != NULL)
357 	free (ptr->Url);
358     if (ptr->Item != NULL)
359 	free (ptr->Item);
360     free (ptr);
361 }
362 
363 static wmsCachedCapabilitiesPtr
wmsAllocCachedCapabilities(const char * url,const unsigned char * response,int size)364 wmsAllocCachedCapabilities (const char *url, const unsigned char *response,
365 			    int size)
366 {
367 /* creating a WMS Cached GetCapabilities response */
368     wmsCachedCapabilitiesPtr ptr = malloc (sizeof (wmsCachedCapabilities));
369     int len = strlen (url);
370     ptr->Url = malloc (len + 1);
371     strcpy (ptr->Url, url);
372     ptr->Response = malloc (size + 1);
373     memcpy (ptr->Response, response, size);
374     *(ptr->Response + size) = '\0';
375     ptr->Next = NULL;
376     return ptr;
377 }
378 
379 static void
wmsFreeCachedCapabilities(wmsCachedCapabilitiesPtr ptr)380 wmsFreeCachedCapabilities (wmsCachedCapabilitiesPtr ptr)
381 {
382 /* memory cleanup - destroying a WMS Cached GetCapabilities Response */
383     if (ptr == NULL)
384 	return;
385     if (ptr->Url != NULL)
386 	free (ptr->Url);
387     if (ptr->Response != NULL)
388 	free (ptr->Response);
389     free (ptr);
390 }
391 
392 static wmsCachePtr
wmsAllocCache(void)393 wmsAllocCache (void)
394 {
395 /* creating a WMS Cache */
396     wmsCachePtr cache = malloc (sizeof (wmsCache));
397     cache->MaxSize = 64 * 1024 * 1024;
398     cache->CurrentSize = 0;
399     cache->FirstCapab = NULL;
400     cache->LastCapab = NULL;
401     cache->First = NULL;
402     cache->Last = NULL;
403     cache->NumCachedItems = 0;
404     cache->SortedByUrl = NULL;
405     cache->SortedByTime = NULL;
406     cache->HitCount = 0;
407     cache->MissCount = 0;
408     cache->FlushedCount = 0;
409     cache->TotalDownload = 0 - 0;
410     return cache;
411 }
412 
413 static void
wmsCacheReset(wmsCachePtr cache)414 wmsCacheReset (wmsCachePtr cache)
415 {
416 /* memory cleanup: flushing/resetting a WMS-Cache object */
417     wmsCachedItemPtr pI;
418     wmsCachedItemPtr pIn;
419     wmsCachedCapabilitiesPtr pC;
420     wmsCachedCapabilitiesPtr pCn;
421     if (cache == NULL)
422 	return;
423 
424     pC = cache->FirstCapab;
425     while (pC != NULL)
426       {
427 	  pCn = pC->Next;
428 	  wmsFreeCachedCapabilities (pC);
429 	  pC = pCn;
430       }
431     pI = cache->First;
432     while (pI != NULL)
433       {
434 	  pIn = pI->Next;
435 	  wmsFreeCachedItem (pI);
436 	  pI = pIn;
437       }
438     if (cache->SortedByUrl != NULL)
439 	free (cache->SortedByUrl);
440     if (cache->SortedByTime != NULL)
441 	free (cache->SortedByTime);
442     cache->CurrentSize = 0;
443     cache->First = NULL;
444     cache->Last = NULL;
445     cache->FirstCapab = NULL;
446     cache->LastCapab = NULL;
447     cache->NumCachedItems = 0;
448     cache->HitCount = 0;
449     cache->MissCount = 0;
450     cache->FlushedCount = 0;
451     cache->TotalDownload = 0.0;
452     cache->SortedByUrl = NULL;
453     cache->SortedByTime = NULL;
454 }
455 
456 static void
wmsFreeCache(wmsCachePtr cache)457 wmsFreeCache (wmsCachePtr cache)
458 {
459 /* memory cleanup: freeing a WMS-Cache object */
460     if (cache == NULL)
461 	return;
462 
463     wmsCacheReset (cache);
464     free (cache);
465 }
466 
467 static int
compare_time(const void * p1,const void * p2)468 compare_time (const void *p1, const void *p2)
469 {
470 /* comparison function for QSort [Time] */
471     wmsCachedItemPtr pI1 = *((wmsCachedItemPtr *) p1);
472     wmsCachedItemPtr pI2 = *((wmsCachedItemPtr *) p2);
473     if (pI1->Time == pI2->Time)
474 	return 0;
475     if (pI1->Time > pI2->Time)
476 	return 1;
477     return -1;
478 }
479 
480 static void
wmsCacheUpdateTime(wmsCachePtr cache)481 wmsCacheUpdateTime (wmsCachePtr cache)
482 {
483 /* updating the SortedByTime array */
484     wmsCachedItemPtr pI;
485     int pos = 0;
486     if (cache == NULL)
487 	return;
488     if (cache->SortedByTime != NULL)
489 	free (cache->SortedByTime);
490     cache->SortedByTime = NULL;
491     if (cache->NumCachedItems <= 0)
492 	return;
493     cache->SortedByTime =
494 	malloc (sizeof (wmsCachedItemPtr) * cache->NumCachedItems);
495     pI = cache->First;
496     while (pI != NULL)
497       {
498 	  /* populating the array */
499 	  *(cache->SortedByTime + pos) = pI;
500 	  pos++;
501 	  pI = pI->Next;
502       }
503     qsort (cache->SortedByTime, cache->NumCachedItems,
504 	   sizeof (wmsCachedItemPtr), compare_time);
505 }
506 
507 static int
compare_url(const void * p1,const void * p2)508 compare_url (const void *p1, const void *p2)
509 {
510 /* comparison function for QSort [Time] */
511     wmsCachedItemPtr pI1 = *((wmsCachedItemPtr *) p1);
512     wmsCachedItemPtr pI2 = *((wmsCachedItemPtr *) p2);
513     return strcmp (pI1->Url, pI2->Url);
514 }
515 
516 static void
wmsCacheUpdate(wmsCachePtr cache)517 wmsCacheUpdate (wmsCachePtr cache)
518 {
519 /* updating the SortedByUrl array */
520     wmsCachedItemPtr pI;
521     int pos = 0;
522     if (cache == NULL)
523 	return;
524     if (cache->SortedByUrl != NULL)
525 	free (cache->SortedByUrl);
526     cache->SortedByUrl = NULL;
527     if (cache->NumCachedItems <= 0)
528 	return;
529     cache->SortedByUrl =
530 	malloc (sizeof (wmsCachedItemPtr) * cache->NumCachedItems);
531     pI = cache->First;
532     while (pI != NULL)
533       {
534 	  /* populating the array */
535 	  *(cache->SortedByUrl + pos) = pI;
536 	  pos++;
537 	  pI = pI->Next;
538       }
539     qsort (cache->SortedByUrl, cache->NumCachedItems, sizeof (wmsCachedItemPtr),
540 	   compare_url);
541 }
542 
543 static void
wmsCacheSqueeze(wmsCachePtr cache,int limit)544 wmsCacheSqueeze (wmsCachePtr cache, int limit)
545 {
546 /* squeezing the WMS Cache */
547     int i;
548     int max;
549     if (cache == NULL)
550 	return;
551     if (cache->CurrentSize < limit)
552 	return;
553     wmsCacheUpdateTime (cache);
554     max = cache->NumCachedItems;
555     for (i = 0; i < max; i++)
556       {
557 	  wmsCachedItemPtr pI = *(cache->SortedByTime + i);
558 	  if (pI->Prev != NULL)
559 	      pI->Prev->Next = pI->Next;
560 	  if (pI->Next != NULL)
561 	      pI->Next->Prev = pI->Prev;
562 	  if (cache->First == pI)
563 	      cache->First = pI->Next;
564 	  if (cache->Last == pI)
565 	      cache->Last = pI->Prev;
566 	  wmsFreeCachedItem (pI);
567 	  cache->NumCachedItems -= 1;
568 	  cache->CurrentSize -= pI->Size;
569 	  cache->FlushedCount += 1;
570 	  if (cache->CurrentSize < limit)
571 	      break;
572       }
573     if (cache->SortedByTime != NULL)
574 	free (cache->SortedByTime);
575     cache->SortedByTime = NULL;
576 }
577 
578 static void
wmsAddCachedCapabilities(wmsCachePtr cache,const char * url,const unsigned char * response,int size)579 wmsAddCachedCapabilities (wmsCachePtr cache, const char *url,
580 			  const unsigned char *response, int size)
581 {
582 /* adding a new WMS Cached GetCapabilitiesItem */
583     wmsCachedCapabilitiesPtr ptr;
584     if (cache == NULL)
585 	return;
586     ptr = wmsAllocCachedCapabilities (url, response, size);
587     if (cache->FirstCapab == NULL)
588 	cache->FirstCapab = ptr;
589     if (cache->LastCapab != NULL)
590 	cache->LastCapab->Next = ptr;
591     cache->LastCapab = ptr;
592     cache->TotalDownload += (double) size;
593 }
594 
595 
596 static void
wmsAddCachedItem(wmsCachePtr cache,const char * url,const unsigned char * item,int size,const char * image_format)597 wmsAddCachedItem (wmsCachePtr cache, const char *url, const unsigned char *item,
598 		  int size, const char *image_format)
599 {
600 /* adding a new WMS Cached Item */
601     wmsCachedItemPtr ptr;
602     if (cache == NULL)
603 	return;
604     if (cache->CurrentSize + size > cache->MaxSize)
605 	wmsCacheSqueeze (cache, cache->MaxSize - size);
606     ptr = wmsAllocCachedItem (url, item, size, image_format);
607     ptr->Prev = cache->Last;
608     if (cache->First == NULL)
609 	cache->First = ptr;
610     if (cache->Last != NULL)
611 	cache->Last->Next = ptr;
612     cache->Last = ptr;
613     cache->NumCachedItems += 1;
614     cache->CurrentSize += size;
615     cache->TotalDownload += (double) size;
616     wmsCacheUpdate (cache);
617 }
618 
619 static wmsCachedCapabilitiesPtr
getWmsCachedCapabilities(wmsCachePtr cache,const char * url)620 getWmsCachedCapabilities (wmsCachePtr cache, const char *url)
621 {
622 /* attempting to retrieve a cached GetCapabilities Response by URL */
623     wmsCachedCapabilitiesPtr capab;
624     if (cache == NULL)
625 	return NULL;
626     capab = cache->FirstCapab;
627     while (capab != NULL)
628       {
629 	  if (strcmp (capab->Url, url) == 0)
630 	      return capab;
631 	  capab = capab->Next;
632       }
633     return NULL;
634 }
635 
636 static wmsCachedItemPtr
getWmsCachedItem(wmsCachePtr cache,const char * url)637 getWmsCachedItem (wmsCachePtr cache, const char *url)
638 {
639 /* attempting to retrieve a cached item by URL */
640     wmsCachedItem item;
641     wmsCachedItemPtr p_item = &item;
642     wmsCachedItemPtr found;
643     void *x;
644     item.Url = (char *) url;
645     if (cache == NULL)
646 	return NULL;
647     if (cache->NumCachedItems <= 0)
648 	return NULL;
649     if (cache->SortedByUrl == NULL)
650 	return NULL;
651     x = bsearch (&p_item, cache->SortedByUrl, cache->NumCachedItems,
652 		 sizeof (wmsCachedItemPtr), compare_url);
653     if (x == NULL)
654       {
655 	  cache->MissCount += 1;
656 	  return NULL;
657       }
658     found = *((wmsCachedItemPtr *) x);
659     cache->HitCount += 1;
660     return found;
661 }
662 
663 RL2_DECLARE rl2WmsCachePtr
create_wms_cache(void)664 create_wms_cache (void)
665 {
666 /* creating a WMS Cache */
667     wmsCachePtr cache = wmsAllocCache ();
668     return (rl2WmsCachePtr) cache;
669 }
670 
671 RL2_DECLARE void
destroy_wms_cache(rl2WmsCachePtr handle)672 destroy_wms_cache (rl2WmsCachePtr handle)
673 {
674 /* memory cleanup: freeing a WMS-Cache object */
675     wmsCachePtr ptr = (wmsCachePtr) handle;
676     if (ptr == NULL)
677 	return;
678     wmsFreeCache (ptr);
679 }
680 
681 RL2_DECLARE void
reset_wms_cache(rl2WmsCachePtr handle)682 reset_wms_cache (rl2WmsCachePtr handle)
683 {
684 /* memory cleanup: flushing/resetting a WMS-Cache object */
685     wmsCachePtr ptr = (wmsCachePtr) handle;
686     if (ptr == NULL)
687 	return;
688     wmsCacheReset (ptr);
689 }
690 
691 RL2_DECLARE int
get_wms_cache_max_size(rl2WmsCachePtr handle)692 get_wms_cache_max_size (rl2WmsCachePtr handle)
693 {
694 /* returns the MAX-SIZE from a WMS-Cache object */
695     wmsCachePtr ptr = (wmsCachePtr) handle;
696     if (ptr == NULL)
697 	return -1;
698     return ptr->MaxSize;
699 }
700 
701 RL2_DECLARE void
set_wms_cache_max_size(rl2WmsCachePtr handle,int size)702 set_wms_cache_max_size (rl2WmsCachePtr handle, int size)
703 {
704 /* changes the MAX-SIZE for a WMS-Cache object */
705     int min = 4 * 1024 * 1024;
706     int max = 256 * 1024 * 1024;
707     wmsCachePtr ptr = (wmsCachePtr) handle;
708     if (ptr == NULL)
709 	return;
710     ptr->MaxSize = size;
711     if (ptr->MaxSize < min)
712 	ptr->MaxSize = min;
713     if (ptr->MaxSize > max)
714 	ptr->MaxSize = max;
715     if (ptr->CurrentSize > ptr->MaxSize)
716       {
717 	  wmsCacheSqueeze (ptr, ptr->MaxSize);
718 	  wmsCacheUpdate (ptr);
719       }
720 }
721 
722 RL2_DECLARE int
get_wms_cache_items_count(rl2WmsCachePtr handle)723 get_wms_cache_items_count (rl2WmsCachePtr handle)
724 {
725 /* returns the CURRENT-SIZE from a WMS-Cache object */
726     wmsCachePtr ptr = (wmsCachePtr) handle;
727     if (ptr == NULL)
728 	return -1;
729     return ptr->NumCachedItems;
730 }
731 
732 RL2_DECLARE int
get_wms_cache_current_size(rl2WmsCachePtr handle)733 get_wms_cache_current_size (rl2WmsCachePtr handle)
734 {
735 /* returns the CURRENT-SIZE from a WMS-Cache object */
736     wmsCachePtr ptr = (wmsCachePtr) handle;
737     if (ptr == NULL)
738 	return -1;
739     return ptr->CurrentSize;
740 }
741 
742 RL2_DECLARE int
get_wms_cache_hit_count(rl2WmsCachePtr handle)743 get_wms_cache_hit_count (rl2WmsCachePtr handle)
744 {
745 /* returns the HIT-COUNT from a WMS-Cache object */
746     wmsCachePtr ptr = (wmsCachePtr) handle;
747     if (ptr == NULL)
748 	return -1;
749     return ptr->HitCount;
750 }
751 
752 RL2_DECLARE int
get_wms_cache_miss_count(rl2WmsCachePtr handle)753 get_wms_cache_miss_count (rl2WmsCachePtr handle)
754 {
755 /* returns the MISS-COUNT from a WMS-Cache object */
756     wmsCachePtr ptr = (wmsCachePtr) handle;
757     if (ptr == NULL)
758 	return -1;
759     return ptr->MissCount;
760 }
761 
762 RL2_DECLARE int
get_wms_cache_flushed_count(rl2WmsCachePtr handle)763 get_wms_cache_flushed_count (rl2WmsCachePtr handle)
764 {
765 /* returns the FLUSHED-COUNT from a WMS-Cache object */
766     wmsCachePtr ptr = (wmsCachePtr) handle;
767     if (ptr == NULL)
768 	return -1;
769     return ptr->FlushedCount;
770 }
771 
772 RL2_DECLARE double
get_wms_total_download_size(rl2WmsCachePtr handle)773 get_wms_total_download_size (rl2WmsCachePtr handle)
774 {
775 /* returns the TOTAL-DOWNLOAD size from a WMS-Cache object */
776     wmsCachePtr ptr = (wmsCachePtr) handle;
777     if (ptr == NULL)
778 	return -1;
779     return ptr->TotalDownload;
780 }
781 
782 static wmsFormatPtr
wmsAllocFormat(const char * format)783 wmsAllocFormat (const char *format)
784 {
785 /* allocating an empty WMS Format object */
786     int len;
787     wmsFormatPtr fmt = malloc (sizeof (wmsFormat));
788     fmt->FormatCode = WMS_FORMAT_UNKNOWN;
789     if (strcmp (format, "image/jpeg") == 0)
790 	fmt->FormatCode = WMS_FORMAT_JPEG;
791     if (strcmp (format, "image/tiff") == 0)
792 	fmt->FormatCode = WMS_FORMAT_TIFF;
793     if (strcmp (format, "image/gif") == 0)
794 	fmt->FormatCode = WMS_FORMAT_GIF;
795     if (strcmp (format, "image/png") == 0)
796 	fmt->FormatCode = WMS_FORMAT_PNG;
797     if (strcmp (format, "image/png8") == 0)
798 	fmt->FormatCode = WMS_FORMAT_PNG8;
799     if (strcmp (format, "image/png; mode=8bit") == 0)
800 	fmt->FormatCode = WMS_FORMAT_PNG8;
801     if (strcmp (format, "image/png24") == 0)
802 	fmt->FormatCode = WMS_FORMAT_PNG24;
803     if (strcmp (format, "image/png; mode=24bit") == 0)
804 	fmt->FormatCode = WMS_FORMAT_PNG24;
805     if (strcmp (format, "image/png32") == 0)
806 	fmt->FormatCode = WMS_FORMAT_PNG32;
807     if (strcmp (format, "image/png; mode=32bit") == 0)
808 	fmt->FormatCode = WMS_FORMAT_PNG32;
809     len = strlen (format);
810     fmt->Format = malloc (len + 1);
811     strcpy (fmt->Format, format);
812     fmt->next = NULL;
813     return fmt;
814 }
815 
816 static void
wmsFreeFormat(wmsFormatPtr fmt)817 wmsFreeFormat (wmsFormatPtr fmt)
818 {
819 /* memory cleanup - destroying a WMS Format object */
820     if (fmt == NULL)
821 	return;
822     if (fmt->Format != NULL)
823 	free (fmt->Format);
824     free (fmt);
825 }
826 
827 static wmsCrsPtr
wmsAllocCrs(const char * crs_str)828 wmsAllocCrs (const char *crs_str)
829 {
830 /* allocating a WMS CRS object */
831     int len;
832     wmsCrsPtr crs = malloc (sizeof (wmsCrs));
833     crs->Crs = NULL;
834     if (crs != NULL)
835       {
836 	  len = strlen (crs_str);
837 	  crs->Crs = malloc (len + 1);
838 	  strcpy (crs->Crs, crs_str);
839       }
840     crs->next = NULL;
841     return crs;
842 }
843 
844 static void
wmsFreeCrs(wmsCrsPtr crs)845 wmsFreeCrs (wmsCrsPtr crs)
846 {
847 /* memory cleanup - destroying a WMS CRS object */
848     if (crs == NULL)
849 	return;
850     if (crs->Crs != NULL)
851 	free (crs->Crs);
852     free (crs);
853 }
854 
855 static wmsBBoxPtr
wmsAllocBBox(const char * crs_str,double minx,double maxx,double miny,double maxy)856 wmsAllocBBox (const char *crs_str, double minx, double maxx, double miny,
857 	      double maxy)
858 {
859 /* allocating a WMS Bounding Box object */
860     int len;
861     wmsBBoxPtr bbox = malloc (sizeof (wmsBBox));
862     bbox->Crs = NULL;
863     if (bbox != NULL)
864       {
865 	  len = strlen (crs_str);
866 	  bbox->Crs = malloc (len + 1);
867 	  strcpy (bbox->Crs, crs_str);
868       }
869     bbox->MinX = minx;
870     bbox->MaxX = maxx;
871     bbox->MinY = miny;
872     bbox->MaxY = maxy;
873     bbox->next = NULL;
874     return bbox;
875 }
876 
877 static void
wmsFreeBBox(wmsBBoxPtr bbox)878 wmsFreeBBox (wmsBBoxPtr bbox)
879 {
880 /* memory cleanup - destroying a WMS BBOX object */
881     if (bbox == NULL)
882 	return;
883     if (bbox->Crs != NULL)
884 	free (bbox->Crs);
885     free (bbox);
886 }
887 
888 static wmsStylePtr
wmsAllocStyle(const char * name,const char * title,const char * abstract)889 wmsAllocStyle (const char *name, const char *title, const char *abstract)
890 {
891 /* allocating a WMS Style object */
892     int len;
893     wmsStylePtr stl = malloc (sizeof (wmsStyle));
894     stl->Name = NULL;
895     stl->Title = NULL;
896     stl->Abstract = NULL;
897     if (name != NULL)
898       {
899 	  len = strlen (name);
900 	  stl->Name = malloc (len + 1);
901 	  strcpy (stl->Name, name);
902       }
903     if (title != NULL)
904       {
905 	  len = strlen (title);
906 	  stl->Title = malloc (len + 1);
907 	  strcpy (stl->Title, title);
908       }
909     if (abstract != NULL)
910       {
911 	  len = strlen (abstract);
912 	  stl->Abstract = malloc (len + 1);
913 	  strcpy (stl->Abstract, abstract);
914       }
915     stl->next = NULL;
916     return stl;
917 }
918 
919 static void
wmsFreeStyle(wmsStylePtr stl)920 wmsFreeStyle (wmsStylePtr stl)
921 {
922 /* memory cleanup - destroying a WMS Style object */
923     if (stl == NULL)
924 	return;
925     if (stl->Name != NULL)
926 	free (stl->Name);
927     if (stl->Title != NULL)
928 	free (stl->Title);
929     if (stl->Abstract != NULL)
930 	free (stl->Abstract);
931     free (stl);
932 }
933 
934 static wmsLayerPtr
wmsAllocLayer(const char * name,const char * title,const char * abstract,wmsLayerPtr parent)935 wmsAllocLayer (const char *name, const char *title, const char *abstract,
936 	       wmsLayerPtr parent)
937 {
938 /* allocating a WMS Layer object */
939     int len;
940     wmsLayerPtr lyr = malloc (sizeof (wmsLayer));
941     lyr->Queryable = -1;
942     lyr->Opaque = -1;
943     lyr->Name = NULL;
944     lyr->Title = NULL;
945     lyr->Abstract = NULL;
946     if (name != NULL)
947       {
948 	  len = strlen (name);
949 	  lyr->Name = malloc (len + 1);
950 	  strcpy (lyr->Name, name);
951       }
952     if (title != NULL)
953       {
954 	  len = strlen (title);
955 	  lyr->Title = malloc (len + 1);
956 	  strcpy (lyr->Title, title);
957       }
958     if (abstract != NULL)
959       {
960 	  len = strlen (abstract);
961 	  lyr->Abstract = malloc (len + 1);
962 	  strcpy (lyr->Abstract, abstract);
963       }
964     lyr->Parent = parent;
965     lyr->MinScaleDenominator = DBL_MAX;
966     lyr->MaxScaleDenominator = DBL_MAX;
967     lyr->MinLat = DBL_MAX;
968     lyr->MaxLat = DBL_MAX;
969     lyr->MinLong = DBL_MAX;
970     lyr->MaxLong = DBL_MAX;
971     lyr->firstBBox = NULL;
972     lyr->lastBBox = NULL;
973     lyr->firstCrs = NULL;
974     lyr->lastCrs = NULL;
975     lyr->firstStyle = NULL;
976     lyr->lastStyle = NULL;
977     lyr->firstLayer = NULL;
978     lyr->lastLayer = NULL;
979     lyr->next = NULL;
980     return lyr;
981 }
982 
983 static void
wmsFreeLayer(wmsLayerPtr lyr)984 wmsFreeLayer (wmsLayerPtr lyr)
985 {
986 /* memory cleanup - destroying a WMS Layer object */
987     wmsCrsPtr pc;
988     wmsCrsPtr pcn;
989     wmsBBoxPtr pbb;
990     wmsBBoxPtr pbbn;
991     wmsStylePtr ps;
992     wmsStylePtr psn;
993     wmsLayerPtr pl;
994     wmsLayerPtr pln;
995     if (lyr == NULL)
996 	return;
997     if (lyr->Name != NULL)
998 	free (lyr->Name);
999     if (lyr->Title != NULL)
1000 	free (lyr->Title);
1001     if (lyr->Abstract != NULL)
1002 	free (lyr->Abstract);
1003     pc = lyr->firstCrs;
1004     while (pc != NULL)
1005       {
1006 	  pcn = pc->next;
1007 	  wmsFreeCrs (pc);
1008 	  pc = pcn;
1009       }
1010     pbb = lyr->firstBBox;
1011     while (pbb != NULL)
1012       {
1013 	  pbbn = pbb->next;
1014 	  wmsFreeBBox (pbb);
1015 	  pbb = pbbn;
1016       }
1017     ps = lyr->firstStyle;
1018     while (ps != NULL)
1019       {
1020 	  psn = ps->next;
1021 	  wmsFreeStyle (ps);
1022 	  ps = psn;
1023       }
1024     pl = lyr->firstLayer;
1025     while (pl != NULL)
1026       {
1027 	  pln = pl->next;
1028 	  wmsFreeLayer (pl);
1029 	  pl = pln;
1030       }
1031     free (lyr);
1032 }
1033 
1034 static wmsUrlArgumentPtr
wmsAllocUrlArgument(char * arg_name,char * arg_value)1035 wmsAllocUrlArgument (char *arg_name, char *arg_value)
1036 {
1037 /* allocating a WMS URL Argument object */
1038     wmsUrlArgumentPtr arg = malloc (sizeof (wmsUrlArgument));
1039     arg->argName = arg_name;
1040     arg->argValue = arg_value;
1041     arg->next = NULL;
1042     return arg;
1043 }
1044 
1045 static void
wmsFreeUrlArgument(wmsUrlArgumentPtr arg)1046 wmsFreeUrlArgument (wmsUrlArgumentPtr arg)
1047 {
1048 /* memory cleanup - destroying a WMS URL Argument object */
1049     if (arg == NULL)
1050 	return;
1051     if (arg->argName != NULL)
1052 	free (arg->argName);
1053     if (arg->argValue != NULL)
1054 	free (arg->argValue);
1055     free (arg);
1056 }
1057 
1058 static void
add_url_argument(wmsTilePatternPtr ptr,const char * pattern)1059 add_url_argument (wmsTilePatternPtr ptr, const char *pattern)
1060 {
1061 /* adding an URL argument */
1062     char *name = NULL;
1063     char *value = NULL;
1064     const char *p = pattern;
1065     const char *p_eq = pattern;
1066     wmsUrlArgumentPtr arg;
1067     int len;
1068 
1069 /* splitting arg Name and Value */
1070     while (1)
1071       {
1072 	  if (*p == '=')
1073 	      p_eq = p;
1074 	  if (*p == '\0')
1075 	      break;
1076 	  p++;
1077       }
1078 
1079     len = p_eq - pattern;
1080     if (len > 0)
1081       {
1082 	  /* arg Name */
1083 	  name = malloc (len + 1);
1084 	  memcpy (name, pattern, len);
1085 	  *(name + len) = '\0';
1086       }
1087     len = strlen (p_eq + 1);
1088     if (len > 0)
1089       {
1090 	  /* arg Value */
1091 	  value = malloc (len + 1);
1092 	  strcpy (value, p_eq + 1);
1093       }
1094 
1095     arg = wmsAllocUrlArgument (name, value);
1096     if (ptr->first == NULL)
1097 	ptr->first = arg;
1098     if (ptr->last != NULL)
1099 	ptr->last->next = arg;
1100     ptr->last = arg;
1101 }
1102 
1103 static void
parse_pattern_bbox(const char * value,double * minx,double * miny,double * maxx,double * maxy)1104 parse_pattern_bbox (const char *value, double *minx, double *miny, double *maxx,
1105 		    double *maxy)
1106 {
1107 /* parsing a BBOX arg [minx,miny,maxx,maxy] */
1108     int step = 0;
1109     const char *p_start = value;
1110     const char *p_end = value;
1111     *minx = DBL_MAX;
1112     *miny = DBL_MAX;
1113     *maxx = DBL_MAX;
1114     *maxy = DBL_MAX;
1115 
1116     while (1)
1117       {
1118 	  if (*p_end == ',' || *p_end == '\0')
1119 	    {
1120 		int len = p_end - p_start;
1121 		char *str = malloc (len + 1);
1122 		memcpy (str, p_start, len);
1123 		*(str + len) = '\0';
1124 		if (step == 0)
1125 		    *minx = atof (str);
1126 		if (step == 1)
1127 		    *miny = atof (str);
1128 		if (step == 2)
1129 		    *maxx = atof (str);
1130 		if (step == 3)
1131 		    *maxy = atof (str);
1132 		step++;
1133 		free (str);
1134 		p_start = p_end + 1;
1135 	    }
1136 	  if (*p_end == '\0')
1137 	      break;
1138 	  p_end++;
1139       }
1140 }
1141 
1142 static void
parse_url_arguments(wmsTilePatternPtr ptr,const char * pattern)1143 parse_url_arguments (wmsTilePatternPtr ptr, const char *pattern)
1144 {
1145 /* parsing URL arguments */
1146     const char *p_start = pattern;
1147     const char *p_end = pattern;
1148     while (1)
1149       {
1150 	  if (*p_end == '&' || *p_end == '\0')
1151 	    {
1152 		int len = p_end - p_start;
1153 		char *arg = malloc (len + 1);
1154 		memcpy (arg, p_start, len);
1155 		*(arg + len) = '\0';
1156 		add_url_argument (ptr, arg);
1157 		free (arg);
1158 		p_start = p_end + 1;
1159 	    }
1160 	  if (*p_end == '\0')
1161 	      break;
1162 	  p_end++;
1163       }
1164 }
1165 
1166 static wmsTilePatternPtr
wmsAllocTilePattern(char * pattern)1167 wmsAllocTilePattern (char *pattern)
1168 {
1169 /* allocating a WMS TilePattern object */
1170     double minx;
1171     double miny;
1172     double maxx;
1173     double maxy;
1174     wmsUrlArgumentPtr pa;
1175     wmsTilePatternPtr ptr = malloc (sizeof (wmsTilePattern));
1176     ptr->Pattern = pattern;
1177     ptr->Format = NULL;
1178     ptr->SRS = NULL;
1179     ptr->Style = NULL;
1180     ptr->TileWidth = 0;
1181     ptr->TileHeight = 0;
1182     ptr->TileBaseX = DBL_MAX;
1183     ptr->TileBaseY = DBL_MAX;
1184     ptr->TileExtentX = DBL_MAX;
1185     ptr->TileExtentY = DBL_MAX;
1186     ptr->first = NULL;
1187     ptr->last = NULL;
1188     parse_url_arguments (ptr, pattern);
1189     ptr->next = NULL;
1190 /* setting explicit values */
1191     pa = ptr->first;
1192     while (pa != NULL)
1193       {
1194 	  if (strcasecmp (pa->argName, "format") == 0)
1195 	      ptr->Format = pa->argValue;
1196 	  if (strcasecmp (pa->argName, "srs") == 0)
1197 	      ptr->SRS = pa->argValue;
1198 	  if (strcasecmp (pa->argName, "styles") == 0)
1199 	      ptr->Style = pa->argValue;
1200 	  if (strcasecmp (pa->argName, "width") == 0)
1201 	      ptr->TileWidth = atoi (pa->argValue);
1202 	  if (strcasecmp (pa->argName, "width") == 0)
1203 	      ptr->TileHeight = atoi (pa->argValue);
1204 	  if (strcasecmp (pa->argName, "bbox") == 0)
1205 	    {
1206 		parse_pattern_bbox (pa->argValue, &minx, &miny, &maxx, &maxy);
1207 		ptr->TileBaseX = minx;	/* leftmost coord */
1208 		ptr->TileBaseY = maxy;	/* topmost coord */
1209 		ptr->TileExtentX = maxx - minx;
1210 		ptr->TileExtentY = maxy - miny;
1211 	    }
1212 	  pa = pa->next;
1213       }
1214     return ptr;
1215 }
1216 
1217 static void
wmsFreeTilePattern(wmsTilePatternPtr pattern)1218 wmsFreeTilePattern (wmsTilePatternPtr pattern)
1219 {
1220 /* memory cleanup - destroying a WMS TilePattern object */
1221     wmsUrlArgumentPtr pa;
1222     wmsUrlArgumentPtr pan;
1223     if (pattern == NULL)
1224 	return;
1225     if (pattern->Pattern != NULL)
1226 	free (pattern->Pattern);
1227     pa = pattern->first;
1228     while (pa != NULL)
1229       {
1230 	  pan = pa->next;
1231 	  wmsFreeUrlArgument (pa);
1232 	  pa = pan;
1233       }
1234     free (pattern);
1235 }
1236 
1237 static wmsTiledLayerPtr
wmsAllocTiledLayer(const char * name,const char * title,const char * abstract)1238 wmsAllocTiledLayer (const char *name, const char *title, const char *abstract)
1239 {
1240 /* allocating a WMS TiledLayer object */
1241     int len;
1242     wmsTiledLayerPtr lyr = malloc (sizeof (wmsTiledLayer));
1243     lyr->Name = NULL;
1244     lyr->Title = NULL;
1245     lyr->Abstract = NULL;
1246     if (name != NULL)
1247       {
1248 	  len = strlen (name);
1249 	  lyr->Name = malloc (len + 1);
1250 	  strcpy (lyr->Name, name);
1251       }
1252     if (title != NULL)
1253       {
1254 	  len = strlen (title);
1255 	  lyr->Title = malloc (len + 1);
1256 	  strcpy (lyr->Title, title);
1257       }
1258     if (abstract != NULL)
1259       {
1260 	  len = strlen (abstract);
1261 	  lyr->Abstract = malloc (len + 1);
1262 	  strcpy (lyr->Abstract, abstract);
1263       }
1264     lyr->MinLat = DBL_MAX;
1265     lyr->MaxLat = DBL_MAX;
1266     lyr->MinLong = DBL_MAX;
1267     lyr->MaxLong = DBL_MAX;
1268     lyr->Pad = NULL;
1269     lyr->Bands = NULL;
1270     lyr->DataType = NULL;
1271     lyr->firstPattern = NULL;
1272     lyr->lastPattern = NULL;
1273     lyr->firstChild = NULL;
1274     lyr->lastChild = NULL;
1275     lyr->next = NULL;
1276     return lyr;
1277 }
1278 
1279 static void
wmsFreeTiledLayer(wmsTiledLayerPtr lyr)1280 wmsFreeTiledLayer (wmsTiledLayerPtr lyr)
1281 {
1282 /* memory cleanup - destroying a WMS TiledLayer object */
1283     wmsTilePatternPtr pp;
1284     wmsTilePatternPtr ppn;
1285     wmsTiledLayerPtr pt;
1286     wmsTiledLayerPtr ptn;
1287     if (lyr == NULL)
1288 	return;
1289     if (lyr->Name != NULL)
1290 	free (lyr->Name);
1291     if (lyr->Title != NULL)
1292 	free (lyr->Title);
1293     if (lyr->Abstract != NULL)
1294 	free (lyr->Abstract);
1295     if (lyr->Pad != NULL)
1296 	free (lyr->Pad);
1297     if (lyr->Bands != NULL)
1298 	free (lyr->Bands);
1299     if (lyr->DataType != NULL)
1300 	free (lyr->DataType);
1301     pp = lyr->firstPattern;
1302     while (pp != NULL)
1303       {
1304 	  ppn = pp->next;
1305 	  wmsFreeTilePattern (pp);
1306 	  pp = ppn;
1307       }
1308     pt = lyr->firstChild;
1309     while (pt != NULL)
1310       {
1311 	  ptn = pt->next;
1312 	  wmsFreeTiledLayer (pt);
1313 	  pt = ptn;
1314       }
1315     free (lyr);
1316 }
1317 
1318 static wmsCapabilitiesPtr
wmsAllocCapabilities()1319 wmsAllocCapabilities ()
1320 {
1321 /* allocating an empty WMS GetCapabilities object */
1322     wmsCapabilitiesPtr cap = malloc (sizeof (wmsCapabilities));
1323     cap->Version = NULL;
1324     cap->Name = NULL;
1325     cap->Title = NULL;
1326     cap->Abstract = NULL;
1327     cap->GetMapURLGet = NULL;
1328     cap->GetMapURLPost = NULL;
1329     cap->GetFeatureInfoURLGet = NULL;
1330     cap->GetFeatureInfoURLPost = NULL;
1331     cap->GetTileServiceURLGet = NULL;
1332     cap->GetTileServiceURLPost = NULL;
1333     cap->GmlMimeType = NULL;
1334     cap->XmlMimeType = NULL;
1335     cap->ContactPerson = NULL;
1336     cap->ContactOrganization = NULL;
1337     cap->ContactPosition = NULL;
1338     cap->PostalAddress = NULL;
1339     cap->City = NULL;
1340     cap->StateProvince = NULL;
1341     cap->PostCode = NULL;
1342     cap->Country = NULL;
1343     cap->VoiceTelephone = NULL;
1344     cap->FaxTelephone = NULL;
1345     cap->EMailAddress = NULL;
1346     cap->Fees = NULL;
1347     cap->AccessConstraints = NULL;
1348     cap->LayerLimit = -1;
1349     cap->MaxWidth = -1;
1350     cap->MaxHeight = -1;
1351     cap->firstFormat = NULL;
1352     cap->lastFormat = NULL;
1353     cap->firstLayer = NULL;
1354     cap->lastLayer = NULL;
1355     cap->TileServiceName = NULL;
1356     cap->TileServiceTitle = NULL;
1357     cap->TileServiceAbstract = NULL;
1358     cap->firstTiled = NULL;
1359     cap->lastTiled = NULL;
1360     return cap;
1361 }
1362 
1363 static void
wmsFreeCapabilities(wmsCapabilitiesPtr cap)1364 wmsFreeCapabilities (wmsCapabilitiesPtr cap)
1365 {
1366 /* memory cleanup - freeing a WMS Capabilities object */
1367     wmsFormatPtr pf;
1368     wmsFormatPtr pfn;
1369     wmsLayerPtr pl;
1370     wmsLayerPtr pln;
1371     wmsTiledLayerPtr pt;
1372     wmsTiledLayerPtr ptn;
1373     if (cap == NULL)
1374 	return;
1375     if (cap->Version)
1376 	free (cap->Version);
1377     if (cap->Name)
1378 	free (cap->Name);
1379     if (cap->Title)
1380 	free (cap->Title);
1381     if (cap->Abstract)
1382 	free (cap->Abstract);
1383     if (cap->GetMapURLGet)
1384 	free (cap->GetMapURLGet);
1385     if (cap->GetMapURLPost)
1386 	free (cap->GetMapURLPost);
1387     if (cap->GetFeatureInfoURLGet)
1388 	free (cap->GetFeatureInfoURLGet);
1389     if (cap->GetFeatureInfoURLPost)
1390 	free (cap->GetFeatureInfoURLPost);
1391     if (cap->GetTileServiceURLGet)
1392 	free (cap->GetTileServiceURLGet);
1393     if (cap->GetTileServiceURLPost)
1394 	free (cap->GetTileServiceURLPost);
1395     if (cap->GmlMimeType)
1396 	free (cap->GmlMimeType);
1397     if (cap->XmlMimeType)
1398 	free (cap->XmlMimeType);
1399     if (cap->ContactPerson)
1400 	free (cap->ContactPerson);
1401     if (cap->ContactOrganization)
1402 	free (cap->ContactOrganization);
1403     if (cap->ContactPosition)
1404 	free (cap->ContactPosition);
1405     if (cap->PostalAddress)
1406 	free (cap->PostalAddress);
1407     if (cap->City)
1408 	free (cap->City);
1409     if (cap->StateProvince)
1410 	free (cap->StateProvince);
1411     if (cap->PostCode)
1412 	free (cap->PostCode);
1413     if (cap->Country)
1414 	free (cap->Country);
1415     if (cap->VoiceTelephone)
1416 	free (cap->VoiceTelephone);
1417     if (cap->FaxTelephone)
1418 	free (cap->FaxTelephone);
1419     if (cap->EMailAddress)
1420 	free (cap->EMailAddress);
1421     if (cap->Fees)
1422 	free (cap->Fees);
1423     if (cap->AccessConstraints)
1424 	free (cap->AccessConstraints);
1425     if (cap->TileServiceName)
1426 	free (cap->TileServiceName);
1427     if (cap->TileServiceTitle)
1428 	free (cap->TileServiceTitle);
1429     if (cap->TileServiceAbstract)
1430 	free (cap->TileServiceAbstract);
1431     pf = cap->firstFormat;
1432     while (pf != NULL)
1433       {
1434 	  pfn = pf->next;
1435 	  wmsFreeFormat (pf);
1436 	  pf = pfn;
1437       }
1438     pl = cap->firstLayer;
1439     while (pl != NULL)
1440       {
1441 	  pln = pl->next;
1442 	  wmsFreeLayer (pl);
1443 	  pl = pln;
1444       }
1445     pt = cap->firstTiled;
1446     while (pt != NULL)
1447       {
1448 	  ptn = pt->next;
1449 	  wmsFreeTiledLayer (pt);
1450 	  pt = ptn;
1451       }
1452     free (cap);
1453 }
1454 
1455 static wmsFeatureAttributePtr
wmsAllocFeatureAttribute(const char * name,char * value)1456 wmsAllocFeatureAttribute (const char *name, char *value)
1457 {
1458 /* allocating and initializing a GML Feature Attribute object */
1459     int len;
1460     wmsFeatureAttributePtr attr = malloc (sizeof (wmsFeatureAttribute));
1461     len = strlen (name);
1462     attr->name = malloc (len + 1);
1463     strcpy (attr->name, name);
1464     attr->value = value;
1465     attr->geometry = NULL;
1466     attr->next = NULL;
1467     return attr;
1468 }
1469 
1470 static void
wmsFreeFeatureAttribute(wmsFeatureAttributePtr attr)1471 wmsFreeFeatureAttribute (wmsFeatureAttributePtr attr)
1472 {
1473 /* memory cleanup - freeing a GML Feature Attribute object */
1474     if (attr == NULL)
1475 	return;
1476     if (attr->name != NULL)
1477 	free (attr->name);
1478     if (attr->value != NULL)
1479 	free (attr->value);
1480     if (attr->geometry != NULL)
1481 	gaiaFreeGeomColl (attr->geometry);
1482     free (attr);
1483 }
1484 
1485 static wmsFeatureMemberPtr
wmsAllocFeatureMember(const char * name)1486 wmsAllocFeatureMember (const char *name)
1487 {
1488 /* allocating an empty GML Feature Member object */
1489     int len;
1490     wmsFeatureMemberPtr member = malloc (sizeof (wmsFeatureMember));
1491     len = strlen (name);
1492     member->layer_name = malloc (len + 1);
1493     strcpy (member->layer_name, name);
1494     member->first = NULL;
1495     member->last = NULL;
1496     member->next = NULL;
1497     return member;
1498 }
1499 
1500 static void
wmsFreeFeatureMember(wmsFeatureMemberPtr member)1501 wmsFreeFeatureMember (wmsFeatureMemberPtr member)
1502 {
1503 /* memory cleanup - freeing a GML Feature Member object */
1504     wmsFeatureAttributePtr pa;
1505     wmsFeatureAttributePtr pan;
1506     if (member == NULL)
1507 	return;
1508     if (member->layer_name != NULL)
1509 	free (member->layer_name);
1510     pa = member->first;
1511     while (pa != NULL)
1512       {
1513 	  pan = pa->next;
1514 	  wmsFreeFeatureAttribute (pa);
1515 	  pa = pan;
1516       }
1517     free (member);
1518 }
1519 
1520 static void
wmsAddFeatureMemberAttribute(wmsFeatureMemberPtr member,const char * name,char * value)1521 wmsAddFeatureMemberAttribute (wmsFeatureMemberPtr member, const char *name,
1522 			      char *value)
1523 {
1524 /* adding an attribute+value to some GML Feature Member */
1525     wmsFeatureAttributePtr attr;
1526     if (member == NULL)
1527 	return;
1528     attr = wmsAllocFeatureAttribute (name, value);
1529     if (member->first == NULL)
1530 	member->first = attr;
1531     if (member->last != NULL)
1532 	member->last->next = attr;
1533     member->last = attr;
1534 }
1535 
1536 static wmsFeatureCollectionPtr
wmsAllocFeatureCollection()1537 wmsAllocFeatureCollection ()
1538 {
1539 /* allocating an empty GML Feature Collection object */
1540     wmsFeatureCollectionPtr coll = malloc (sizeof (wmsFeatureCollection));
1541     coll->first = NULL;
1542     coll->last = NULL;
1543     return coll;
1544 }
1545 
1546 static void
wmsFreeFeatureCollection(wmsFeatureCollectionPtr coll)1547 wmsFreeFeatureCollection (wmsFeatureCollectionPtr coll)
1548 {
1549 /* memory cleanup - freeing a GML Feature Collection object */
1550     wmsFeatureMemberPtr pm;
1551     wmsFeatureMemberPtr pmn;
1552     if (coll == NULL)
1553 	return;
1554     pm = coll->first;
1555     while (pm != NULL)
1556       {
1557 	  pmn = pm->next;
1558 	  wmsFreeFeatureMember (pm);
1559 	  pm = pmn;
1560       }
1561     free (coll);
1562 }
1563 
1564 static wmsSinglePartResponsePtr
wmsAllocSinglePartResponse(char * body)1565 wmsAllocSinglePartResponse (char *body)
1566 {
1567 /* allocating and initializing a SinglePart Response */
1568     wmsSinglePartResponsePtr single = malloc (sizeof (wmsSinglePartResponse));
1569     single->body = body;
1570     single->next = NULL;
1571     return single;
1572 }
1573 
1574 static void
wmsFreeSinglePartResponse(wmsSinglePartResponsePtr single)1575 wmsFreeSinglePartResponse (wmsSinglePartResponsePtr single)
1576 {
1577 /* memory cleanup - freeing a HTTP SinglePart Response object */
1578     if (single == NULL)
1579 	return;
1580     if (single->body != NULL)
1581 	free (single->body);
1582     free (single);
1583 }
1584 
1585 static wmsMultipartCollectionPtr
wmsAllocMultipartCollection()1586 wmsAllocMultipartCollection ()
1587 {
1588 /* allocating an empty HTTP Multipart response object */
1589     wmsMultipartCollectionPtr coll = malloc (sizeof (wmsMultipartCollection));
1590     coll->first = NULL;
1591     coll->last = NULL;
1592     return coll;
1593 }
1594 
1595 static void
wmsFreeMultipartCollection(wmsMultipartCollectionPtr coll)1596 wmsFreeMultipartCollection (wmsMultipartCollectionPtr coll)
1597 {
1598 /* memory cleanup - freeing a HTTP Multipart Collection object */
1599     wmsSinglePartResponsePtr ps;
1600     wmsSinglePartResponsePtr psn;
1601     if (coll == NULL)
1602 	return;
1603     ps = coll->first;
1604     while (ps != NULL)
1605       {
1606 	  psn = ps->next;
1607 	  wmsFreeSinglePartResponse (ps);
1608 	  ps = psn;
1609       }
1610     free (coll);
1611 }
1612 
1613 static void
wmsAddPartToMultipart(wmsMultipartCollectionPtr coll,char * body)1614 wmsAddPartToMultipart (wmsMultipartCollectionPtr coll, char *body)
1615 {
1616 /* adding a SinglePart Response to the Collection */
1617     wmsSinglePartResponsePtr single = wmsAllocSinglePartResponse (body);
1618     if (coll->first == NULL)
1619 	coll->first = single;
1620     if (coll->last != NULL)
1621 	coll->last->next = single;
1622     coll->last = single;
1623 }
1624 
1625 static void
wmsMemBufferInitialize(wmsMemBufferPtr buf)1626 wmsMemBufferInitialize (wmsMemBufferPtr buf)
1627 {
1628 /* initializing a dynamically growing output buffer */
1629     buf->Buffer = NULL;
1630     buf->WriteOffset = 0;
1631     buf->BufferSize = 0;
1632     buf->Error = 0;
1633 }
1634 
1635 static void
wmsMemBufferReset(wmsMemBufferPtr buf)1636 wmsMemBufferReset (wmsMemBufferPtr buf)
1637 {
1638 /* cleaning a dynamically growing output buffer */
1639     if (buf->Buffer)
1640 	free (buf->Buffer);
1641     buf->Buffer = NULL;
1642     buf->WriteOffset = 0;
1643     buf->BufferSize = 0;
1644     buf->Error = 0;
1645 }
1646 
1647 static void
wmsMemBufferAppend(wmsMemBufferPtr buf,const unsigned char * payload,size_t size)1648 wmsMemBufferAppend (wmsMemBufferPtr buf, const unsigned char *payload,
1649 		    size_t size)
1650 {
1651 /* appending into the buffer */
1652     size_t free_size = buf->BufferSize - buf->WriteOffset;
1653     if (size > free_size)
1654       {
1655 	  /* we must allocate a bigger buffer */
1656 	  size_t new_size;
1657 	  unsigned char *new_buf;
1658 	  if (buf->BufferSize == 0)
1659 	      new_size = size + 1024;
1660 	  else if (buf->BufferSize <= 4196)
1661 	      new_size = buf->BufferSize + size + 4196;
1662 	  else if (buf->BufferSize <= 65536)
1663 	      new_size = buf->BufferSize + size + 65536;
1664 	  else
1665 	      new_size = buf->BufferSize + size + (1024 * 1024);
1666 	  new_buf = malloc (new_size);
1667 	  if (!new_buf)
1668 	    {
1669 		buf->Error = 1;
1670 		return;
1671 	    }
1672 	  if (buf->Buffer)
1673 	    {
1674 		memcpy (new_buf, buf->Buffer, buf->WriteOffset);
1675 		free (buf->Buffer);
1676 	    }
1677 	  buf->Buffer = new_buf;
1678 	  buf->BufferSize = new_size;
1679       }
1680     memcpy (buf->Buffer + buf->WriteOffset, payload, size);
1681     buf->WriteOffset += size;
1682 }
1683 
1684 static wmsMultipartCollectionPtr
parse_multipart_body(wmsMemBufferPtr buf,const char * multipart_boundary)1685 parse_multipart_body (wmsMemBufferPtr buf, const char *multipart_boundary)
1686 {
1687 /* attempting to split a Multipart Response in its single parts */
1688     const char *p_in;
1689     char *marker = sqlite3_mprintf ("--%s\r\n", multipart_boundary);
1690     char *marker_end = sqlite3_mprintf ("--%s--\r\n", multipart_boundary);
1691     wmsMultipartCollectionPtr coll = wmsAllocMultipartCollection ();
1692 /* ensuring a NULL terminated string */
1693     if (buf->BufferSize > buf->WriteOffset)
1694 	*(buf->Buffer + buf->WriteOffset) = '\0';
1695     else
1696 	wmsMemBufferAppend (buf, (const unsigned char *) " ", 2);
1697     p_in = (const char *) buf->Buffer;
1698     while (p_in != NULL)
1699       {
1700 	  int len;
1701 	  const char *start_body;
1702 	  const char *stop;
1703 	  const char *start = strstr (p_in, marker);
1704 	  if (start == NULL)
1705 	      break;
1706 	  start_body = strstr (start, "\r\n\r\n");
1707 	  if (start_body == NULL)
1708 	      break;
1709 	  start_body += 4;
1710 	  stop = strstr (start_body, marker);
1711 	  if (stop != NULL)
1712 	      p_in = stop;
1713 	  else
1714 	    {
1715 		stop = strstr (start_body, marker_end);
1716 		if (stop == NULL)
1717 		    break;
1718 		p_in = NULL;
1719 	    }
1720 	  stop -= 1;
1721 	  len = stop - start_body + 1;
1722 	  if (len > 0)
1723 	    {
1724 		char *body;
1725 		body = malloc (len + 1);
1726 		memcpy (body, start_body, len);
1727 		*(body + len) = '\0';
1728 		wmsAddPartToMultipart (coll, body);
1729 	    }
1730       }
1731     sqlite3_free (marker);
1732     sqlite3_free (marker_end);
1733     if (coll->first == NULL)
1734       {
1735 	  wmsFreeMultipartCollection (coll);
1736 	  return NULL;
1737       }
1738     return coll;
1739 }
1740 
1741 static size_t
store_data(char * ptr,size_t size,size_t nmemb,void * userdata)1742 store_data (char *ptr, size_t size, size_t nmemb, void *userdata)
1743 {
1744 /* updating the dynamic buffer */
1745     size_t total = size * nmemb;
1746     wmsMemBufferAppend (userdata, (unsigned char *) ptr, total);
1747     return total;
1748 }
1749 
1750 static char *
parse_http_format(wmsMemBufferPtr buf)1751 parse_http_format (wmsMemBufferPtr buf)
1752 {
1753 /* parsing the Content-Type from the HTTP header */
1754     int i;
1755     unsigned char *p_in = NULL;
1756     unsigned char *base;
1757     int size = 0;
1758     char *tmp;
1759 
1760     if (buf->Buffer == NULL)
1761 	return NULL;
1762     for (i = 0; i < (int) (buf->WriteOffset) - 15; i++)
1763       {
1764 	  if (memcmp (buf->Buffer + i, "Content-Type: ", 14) == 0)
1765 	    {
1766 		p_in = buf->Buffer + i + 14;
1767 		break;
1768 	    }
1769       }
1770     if (p_in == NULL)
1771 	return NULL;
1772 
1773 /* attempting to retrieve the Content-Type */
1774     base = p_in;
1775     while ((size_t) (p_in - buf->Buffer) < buf->WriteOffset)
1776       {
1777 	  if (*p_in == '\r')
1778 	      break;
1779 	  size++;
1780 	  p_in++;
1781       }
1782     if (size <= 0)
1783 	return NULL;
1784     tmp = malloc (size + 1);
1785     memcpy (tmp, base, size);
1786     *(tmp + size) = '\0';
1787     return tmp;
1788 }
1789 
1790 static char *
parse_http_redirect(wmsMemBufferPtr buf)1791 parse_http_redirect (wmsMemBufferPtr buf)
1792 {
1793 /* parsing a redirect location from the HTTP header */
1794     int i;
1795     unsigned char *p_in = NULL;
1796     unsigned char *base;
1797     int size = 0;
1798     char *tmp;
1799 
1800     if (buf->Buffer == NULL)
1801 	return NULL;
1802     for (i = 0; i < (int) (buf->WriteOffset) - 11; i++)
1803       {
1804 	  if (memcmp (buf->Buffer + i, "Location: ", 10) == 0)
1805 	    {
1806 		p_in = buf->Buffer + i + 10;
1807 		break;
1808 	    }
1809       }
1810     if (p_in == NULL)
1811 	return NULL;
1812 
1813 /* attempting to retrieve the new HTTP location */
1814     base = p_in;
1815     while ((size_t) (p_in - buf->Buffer) < buf->WriteOffset)
1816       {
1817 	  if (*p_in == '\r')
1818 	      break;
1819 	  size++;
1820 	  p_in++;
1821       }
1822     if (size <= 0)
1823 	return NULL;
1824     tmp = malloc (size + 1);
1825     memcpy (tmp, base, size);
1826     *(tmp + size) = '\0';
1827     return tmp;
1828 }
1829 
1830 static void
check_http_header(wmsMemBufferPtr buf,int * http_status,char ** http_code)1831 check_http_header (wmsMemBufferPtr buf, int *http_status, char **http_code)
1832 {
1833 /* checking the HTTP header */
1834     unsigned char *p_in;
1835     unsigned char *base_status;
1836     unsigned char *base_code;
1837     int size_status = 0;
1838     int size_code = 0;
1839     char *tmp;
1840 
1841     *http_status = -1;
1842     *http_code = NULL;
1843     if (buf->Buffer == NULL)
1844 	return;
1845     if (buf->WriteOffset < 10)
1846 	return;
1847     if (memcmp (buf->Buffer, "HTTP/1.1 ", 9) != 0
1848 	&& memcmp (buf->Buffer, "HTTP/1.0 ", 9) != 0)
1849 	return;
1850 
1851 /* attempting to retrieve the HTTP status */
1852     p_in = buf->Buffer + 9;
1853     base_status = p_in;
1854     while ((size_t) (p_in - buf->Buffer) < buf->WriteOffset)
1855       {
1856 	  if (*p_in == ' ')
1857 	      break;
1858 	  size_status++;
1859 	  p_in++;
1860       }
1861     if (size_status <= 0)
1862 	return;
1863     tmp = malloc (size_status + 1);
1864     memcpy (tmp, base_status, size_status);
1865     *(tmp + size_status) = '\0';
1866     *http_status = atoi (tmp);
1867     free (tmp);
1868 
1869 /* attempting to retrieve the HTTP code */
1870     p_in = buf->Buffer + 10 + size_status;
1871     base_code = p_in;
1872     while ((size_t) (p_in - buf->Buffer) < buf->WriteOffset)
1873       {
1874 	  if (*p_in == '\r')
1875 	      break;
1876 	  size_code++;
1877 	  p_in++;
1878       }
1879     if (size_code <= 0)
1880 	return;
1881     tmp = malloc (size_code + 1);
1882     memcpy (tmp, base_code, size_code);
1883     *(tmp + size_code) = '\0';
1884     *http_code = tmp;
1885 }
1886 
1887 static char *
check_http_multipart_response(wmsMemBufferPtr buf)1888 check_http_multipart_response (wmsMemBufferPtr buf)
1889 {
1890 /* testing for a Content-Type: multipart returning an eventual Boundary delimiter */
1891     int i;
1892     unsigned char *p_in = NULL;
1893     unsigned char *base;
1894     int size = 0;
1895     char *mime;
1896     const char *boundary;
1897     char *tmp;
1898 
1899     if (buf->Buffer == NULL)
1900 	return NULL;
1901     for (i = 0; i < (int) (buf->WriteOffset) - 15; i++)
1902       {
1903 	  if (memcmp (buf->Buffer + i, "Content-Type: ", 14) == 0)
1904 	    {
1905 		p_in = buf->Buffer + i + 14;
1906 		break;
1907 	    }
1908       }
1909     if (p_in == NULL)
1910 	return NULL;
1911 
1912 /* attempting to retrieve the Content-Type */
1913     base = p_in;
1914     while ((size_t) (p_in - buf->Buffer) < buf->WriteOffset)
1915       {
1916 	  if (*p_in == '\r')
1917 	      break;
1918 	  size++;
1919 	  p_in++;
1920       }
1921     if (size <= 0)
1922 	return NULL;
1923     mime = malloc (size + 1);
1924     memcpy (mime, base, size);
1925     *(mime + size) = '\0';
1926     if (strncmp (mime, "multipart/", 10) != 0)
1927 	goto not_found;
1928     boundary = strstr (mime, "boundary=");
1929     if (boundary == NULL)
1930 	goto not_found;
1931 /* attempting to retrieve the Boundary */
1932     size = strlen (boundary + 9);
1933     if (size <= 0)
1934 	goto not_found;
1935     tmp = malloc (size + 1);
1936     strcpy (tmp, boundary + 9);
1937     free (mime);
1938     return tmp;
1939   not_found:
1940     free (mime);
1941     return NULL;
1942 }
1943 
1944 static int
start_cdata(const char * p_in,int i,int max)1945 start_cdata (const char *p_in, int i, int max)
1946 {
1947 /* testing for "<!CDATA[" - CDATA start marker */
1948     if (i + 9 >= max)
1949 	return 0;
1950     if (*(p_in + i) == '<' && *(p_in + i + 1) == '!' && *(p_in + i + 2) == '['
1951 	&& *(p_in + i + 3) == 'C' && *(p_in + i + 4) == 'D'
1952 	&& *(p_in + i + 5) == 'A' && *(p_in + i + 6) == 'T'
1953 	&& *(p_in + i + 7) == 'A' && *(p_in + i + 8) == '[')
1954 	return 1;
1955     return 0;
1956 }
1957 
1958 static int
end_cdata(const char * p_in,int i)1959 end_cdata (const char *p_in, int i)
1960 {
1961 /* testing for "]]>" - CDATA end marker */
1962     if (i < 2)
1963 	return 0;
1964     if (*(p_in + i - 2) == ']' && *(p_in + i - 1) == ']' && *(p_in + i) == '>')
1965 	return 1;
1966     return 0;
1967 }
1968 
1969 static char *
clean_xml(wmsMemBuffer * in)1970 clean_xml (wmsMemBuffer * in)
1971 {
1972 /* cleaning the XML payload by removing useless whitespaces */
1973     wmsMemBuffer outbuf;
1974     char *out;
1975     const char *p_in;
1976     int i;
1977     int j;
1978     int cdata = 0;
1979     int ignore = 0;
1980     if (in->WriteOffset <= 0)
1981 	return NULL;
1982     wmsMemBufferInitialize (&outbuf);
1983 
1984     p_in = (const char *) (in->Buffer);
1985     for (i = 0; i < (int) (in->WriteOffset); i++)
1986       {
1987 	  if (*(p_in + i) == '<')
1988 	    {
1989 		if (!cdata)
1990 		  {
1991 		      if (start_cdata (p_in, i, in->WriteOffset))
1992 			{
1993 			    i += 8;
1994 			    cdata = 1;
1995 			    continue;
1996 			}
1997 		      for (j = outbuf.WriteOffset - 1; j > 0; j--)
1998 			{
1999 			    /* consuming trailing whitespaces */
2000 			    if (*(outbuf.Buffer + j) == ' '
2001 				|| *(outbuf.Buffer + j) == '\t'
2002 				|| *(outbuf.Buffer + j) == '\r'
2003 				|| *(outbuf.Buffer + j) == '\n')
2004 			      {
2005 				  outbuf.WriteOffset -= 1;
2006 				  continue;
2007 			      }
2008 			    break;
2009 			}
2010 		      ignore = 0;
2011 		  }
2012 	    }
2013 	  if (ignore)
2014 	    {
2015 		if (*(p_in + i) == ' ' || *(p_in + i) == '\t'
2016 		    || *(p_in + i) == '\r' || *(p_in + i) == '\n')
2017 		    continue;
2018 		else
2019 		    ignore = 0;
2020 	    }
2021 	  if (*(p_in + i) == '>' && cdata && end_cdata (p_in, i))
2022 	    {
2023 		cdata = 0;
2024 		outbuf.WriteOffset -= 2;
2025 		continue;
2026 	    }
2027 	  if (cdata)
2028 	    {
2029 		/* masking XML special characters */
2030 		if (*(p_in + i) == '<')
2031 		    wmsMemBufferAppend (&outbuf, (const unsigned char *) "&lt;",
2032 					4);
2033 		else if (*(p_in + i) == '>')
2034 		    wmsMemBufferAppend (&outbuf, (const unsigned char *) "&gt;",
2035 					4);
2036 		else if (*(p_in + i) == '&')
2037 		    wmsMemBufferAppend (&outbuf,
2038 					(const unsigned char *) "&amp;", 5);
2039 		else if (*(p_in + i) == '>')
2040 		    wmsMemBufferAppend (&outbuf,
2041 					(const unsigned char *) "&quot;", 6);
2042 		else
2043 		    wmsMemBufferAppend (&outbuf,
2044 					(const unsigned char *) (p_in + i), 1);
2045 	    }
2046 	  else
2047 	      wmsMemBufferAppend (&outbuf, (const unsigned char *) (p_in + i),
2048 				  1);
2049 	  if (*(p_in + i) == '>')
2050 	    {
2051 		if (!cdata)
2052 		    ignore = 1;
2053 	    }
2054       }
2055     out = malloc (outbuf.WriteOffset + 1);
2056     memcpy (out, outbuf.Buffer, outbuf.WriteOffset);
2057     *(out + outbuf.WriteOffset) = '\0';
2058     wmsMemBufferReset (&outbuf);
2059     return out;
2060 }
2061 
2062 static char *
clean_xml_str(const char * p_in)2063 clean_xml_str (const char *p_in)
2064 {
2065 /* cleaning the XML payload by removing useless whitespaces */
2066     wmsMemBuffer outbuf;
2067     char *out;
2068     int i;
2069     int j;
2070     int cdata = 0;
2071     int ignore = 0;
2072     int len = strlen (p_in);
2073     if (len <= 0)
2074 	return NULL;
2075     wmsMemBufferInitialize (&outbuf);
2076 
2077     for (i = 0; i < len; i++)
2078       {
2079 	  if (*(p_in + i) == '<')
2080 	    {
2081 		if (!cdata)
2082 		  {
2083 		      if (start_cdata (p_in, i, len))
2084 			{
2085 			    i += 8;
2086 			    cdata = 1;
2087 			    continue;
2088 			}
2089 		      for (j = outbuf.WriteOffset - 1; j > 0; j--)
2090 			{
2091 			    /* consuming trailing whitespaces */
2092 			    if (*(outbuf.Buffer + j) == ' '
2093 				|| *(outbuf.Buffer + j) == '\t'
2094 				|| *(outbuf.Buffer + j) == '\r'
2095 				|| *(outbuf.Buffer + j) == '\n')
2096 			      {
2097 				  outbuf.WriteOffset -= 1;
2098 				  continue;
2099 			      }
2100 			    break;
2101 			}
2102 		      ignore = 0;
2103 		  }
2104 	    }
2105 	  if (ignore)
2106 	    {
2107 		if (*(p_in + i) == ' ' || *(p_in + i) == '\t'
2108 		    || *(p_in + i) == '\r' || *(p_in + i) == '\n')
2109 		    continue;
2110 		else
2111 		    ignore = 0;
2112 	    }
2113 	  if (*(p_in + i) == '>' && cdata && end_cdata (p_in, i))
2114 	    {
2115 		cdata = 0;
2116 		outbuf.WriteOffset -= 2;
2117 		continue;
2118 	    }
2119 	  if (cdata)
2120 	    {
2121 		/* masking XML special characters */
2122 		if (*(p_in + i) == '<')
2123 		    wmsMemBufferAppend (&outbuf, (const unsigned char *) "&lt;",
2124 					4);
2125 		else if (*(p_in + i) == '>')
2126 		    wmsMemBufferAppend (&outbuf, (const unsigned char *) "&gt;",
2127 					4);
2128 		else if (*(p_in + i) == '&')
2129 		    wmsMemBufferAppend (&outbuf,
2130 					(const unsigned char *) "&amp;", 5);
2131 		else if (*(p_in + i) == '>')
2132 		    wmsMemBufferAppend (&outbuf,
2133 					(const unsigned char *) "&quot;", 6);
2134 		else
2135 		    wmsMemBufferAppend (&outbuf,
2136 					(const unsigned char *) (p_in + i), 1);
2137 	    }
2138 	  else
2139 	      wmsMemBufferAppend (&outbuf, (const unsigned char *) (p_in + i),
2140 				  1);
2141 	  if (*(p_in + i) == '>')
2142 	    {
2143 		if (!cdata)
2144 		    ignore = 1;
2145 	    }
2146       }
2147     out = malloc (outbuf.WriteOffset + 1);
2148     memcpy (out, outbuf.Buffer, outbuf.WriteOffset);
2149     *(out + outbuf.WriteOffset) = '\0';
2150     wmsMemBufferReset (&outbuf);
2151     return out;
2152 }
2153 
2154 static void
wmsParsingError(void * ctx,const char * msg,...)2155 wmsParsingError (void *ctx, const char *msg, ...)
2156 {
2157 /* appending to the current Parsing Error buffer */
2158     wmsMemBufferPtr buf = (wmsMemBufferPtr) ctx;
2159     char out[65536];
2160     va_list args;
2161 
2162     if (ctx != NULL)
2163 	ctx = NULL;		/* suppressing stupid compiler warnings (unused args) */
2164 
2165     va_start (args, msg);
2166     vsnprintf (out, 65536, msg, args);
2167     wmsMemBufferAppend (buf, (unsigned char *) out, strlen (out));
2168     va_end (args);
2169 }
2170 
2171 static void
parse_wms_EX_geoBBox(xmlNodePtr node,wmsLayerPtr lyr)2172 parse_wms_EX_geoBBox (xmlNodePtr node, wmsLayerPtr lyr)
2173 {
2174 /* parsing a WMS Layer/EX_GeographicBoundingBox */
2175     xmlNodePtr cur_node = NULL;
2176     xmlNodePtr child_node = NULL;
2177 
2178     for (cur_node = node; cur_node; cur_node = cur_node->next)
2179       {
2180 	  if (cur_node->type == XML_ELEMENT_NODE)
2181 	    {
2182 		if (strcmp
2183 		    ((const char *) (cur_node->name),
2184 		     "southBoundLatitude") == 0)
2185 		  {
2186 		      child_node = cur_node->children;
2187 		      if (child_node != NULL)
2188 			{
2189 			    if (child_node->type == XML_TEXT_NODE)
2190 				lyr->MinLat =
2191 				    atof ((const char *) (child_node->content));
2192 			}
2193 		  }
2194 		if (strcmp
2195 		    ((const char *) (cur_node->name),
2196 		     "northBoundLatitude") == 0)
2197 		  {
2198 		      child_node = cur_node->children;
2199 		      if (child_node != NULL)
2200 			{
2201 			    if (child_node->type == XML_TEXT_NODE)
2202 				lyr->MaxLat =
2203 				    atof ((const char *) (child_node->content));
2204 			}
2205 		  }
2206 		if (strcmp
2207 		    ((const char *) (cur_node->name),
2208 		     "westBoundLongitude") == 0)
2209 		  {
2210 		      child_node = cur_node->children;
2211 		      if (child_node != NULL)
2212 			{
2213 			    if (child_node->type == XML_TEXT_NODE)
2214 				lyr->MinLong =
2215 				    atof ((const char *) (child_node->content));
2216 			}
2217 		  }
2218 		if (strcmp
2219 		    ((const char *) (cur_node->name),
2220 		     "eastBoundLongitude") == 0)
2221 		  {
2222 		      child_node = cur_node->children;
2223 		      if (child_node != NULL)
2224 			{
2225 			    if (child_node->type == XML_TEXT_NODE)
2226 				lyr->MaxLong =
2227 				    atof ((const char *) (child_node->content));
2228 			}
2229 		  }
2230 	    }
2231       }
2232 }
2233 
2234 static void
parse_wms_geoBBox(struct _xmlAttr * properties,wmsLayerPtr lyr)2235 parse_wms_geoBBox (struct _xmlAttr *properties, wmsLayerPtr lyr)
2236 {
2237 /* parsing a WMS Layer/LatLonBoundingBox */
2238     struct _xmlAttr *attr = properties;
2239 
2240     while (attr != NULL)
2241       {
2242 	  if (attr->name != NULL)
2243 	    {
2244 		xmlNodePtr text;
2245 		if (strcmp ((const char *) (attr->name), "miny") == 0)
2246 		  {
2247 		      text = attr->children;
2248 		      if (text->type == XML_TEXT_NODE)
2249 			  lyr->MinLat = atof ((const char *) (text->content));
2250 		  }
2251 		if (strcmp ((const char *) (attr->name), "maxy") == 0)
2252 		  {
2253 		      text = attr->children;
2254 		      if (text->type == XML_TEXT_NODE)
2255 			  lyr->MaxLat = atof ((const char *) (text->content));
2256 		  }
2257 		if (strcmp ((const char *) (attr->name), "minx") == 0)
2258 		  {
2259 		      text = attr->children;
2260 		      if (text->type == XML_TEXT_NODE)
2261 			  lyr->MinLong = atof ((const char *) (text->content));
2262 		  }
2263 		if (strcmp ((const char *) (attr->name), "maxx") == 0)
2264 		  {
2265 		      text = attr->children;
2266 		      if (text->type == XML_TEXT_NODE)
2267 			  lyr->MaxLong = atof ((const char *) (text->content));
2268 		  }
2269 	    }
2270 	  attr = attr->next;
2271       }
2272 }
2273 
2274 static void
parse_wms_BBox(struct _xmlAttr * properties,wmsLayerPtr lyr)2275 parse_wms_BBox (struct _xmlAttr *properties, wmsLayerPtr lyr)
2276 {
2277 /* parsing a WMS Layer/BoundingBox */
2278     struct _xmlAttr *attr = properties;
2279     const char *crs = NULL;
2280     double minx = DBL_MAX;
2281     double maxx = DBL_MAX;
2282     double miny = DBL_MAX;
2283     double maxy = DBL_MAX;
2284     wmsBBoxPtr bbox;
2285 
2286     while (attr != NULL)
2287       {
2288 	  if (attr->name != NULL)
2289 	    {
2290 		xmlNodePtr text;
2291 		if (strcmp ((const char *) (attr->name), "CRS") == 0
2292 		    || strcmp ((const char *) (attr->name), "SRS") == 0)
2293 		  {
2294 		      text = attr->children;
2295 		      if (text->type == XML_TEXT_NODE)
2296 			  crs = (const char *) (text->content);
2297 		  }
2298 		if (strcmp ((const char *) (attr->name), "miny") == 0)
2299 		  {
2300 		      text = attr->children;
2301 		      if (text->type == XML_TEXT_NODE)
2302 			  miny = atof ((const char *) (text->content));
2303 		  }
2304 		if (strcmp ((const char *) (attr->name), "maxy") == 0)
2305 		  {
2306 		      text = attr->children;
2307 		      if (text->type == XML_TEXT_NODE)
2308 			  maxy = atof ((const char *) (text->content));
2309 		  }
2310 		if (strcmp ((const char *) (attr->name), "minx") == 0)
2311 		  {
2312 		      text = attr->children;
2313 		      if (text->type == XML_TEXT_NODE)
2314 			  minx = atof ((const char *) (text->content));
2315 		  }
2316 		if (strcmp ((const char *) (attr->name), "maxx") == 0)
2317 		  {
2318 		      text = attr->children;
2319 		      if (text->type == XML_TEXT_NODE)
2320 			  maxx = atof ((const char *) (text->content));
2321 		  }
2322 	    }
2323 	  attr = attr->next;
2324       }
2325     bbox = wmsAllocBBox (crs, minx, maxx, miny, maxy);
2326     if (lyr->firstBBox == NULL)
2327 	lyr->firstBBox = bbox;
2328     if (lyr->lastBBox != NULL)
2329 	lyr->lastBBox->next = bbox;
2330     lyr->lastBBox = bbox;
2331 }
2332 
2333 static void
parse_wms_style(xmlNodePtr node,wmsLayerPtr lyr)2334 parse_wms_style (xmlNodePtr node, wmsLayerPtr lyr)
2335 {
2336 /* parsing a WMS Style definition */
2337     xmlNodePtr cur_node = NULL;
2338     xmlNodePtr child_node = NULL;
2339     const char *name = NULL;
2340     const char *title = NULL;
2341     const char *abstract = NULL;
2342     wmsStylePtr stl;
2343 
2344     for (cur_node = node; cur_node; cur_node = cur_node->next)
2345       {
2346 	  if (cur_node->type == XML_ELEMENT_NODE)
2347 	    {
2348 		if (strcmp ((const char *) (cur_node->name), "Name") == 0)
2349 		  {
2350 		      child_node = cur_node->children;
2351 		      if (child_node != NULL)
2352 			{
2353 			    if (child_node->type == XML_TEXT_NODE)
2354 				name = (const char *) (child_node->content);
2355 			}
2356 		  }
2357 		if (strcmp ((const char *) (cur_node->name), "Title") == 0)
2358 		  {
2359 		      child_node = cur_node->children;
2360 		      if (child_node != NULL)
2361 			{
2362 			    if (child_node->type == XML_TEXT_NODE)
2363 				title = (const char *) (child_node->content);
2364 			}
2365 		  }
2366 		if (strcmp ((const char *) (cur_node->name), "Abstract") == 0)
2367 		  {
2368 		      child_node = cur_node->children;
2369 		      if (child_node != NULL)
2370 			{
2371 			    if (child_node->type == XML_TEXT_NODE)
2372 				abstract = (const char *) (child_node->content);
2373 			}
2374 		  }
2375 	    }
2376       }
2377 
2378     stl = wmsAllocStyle (name, title, abstract);
2379     if (lyr->firstStyle == NULL)
2380 	lyr->firstStyle = stl;
2381     if (lyr->lastStyle != NULL)
2382 	lyr->lastStyle->next = stl;
2383     lyr->lastStyle = stl;
2384 }
2385 
2386 static void
parse_wms_layer_in_layer(xmlNodePtr node,struct _xmlAttr * properties,wmsLayerPtr group,int level)2387 parse_wms_layer_in_layer (xmlNodePtr node, struct _xmlAttr *properties,
2388 			  wmsLayerPtr group, int level)
2389 {
2390 /* recursively parsing a WMS Layer definition (2nd level) */
2391     xmlNodePtr cur_node = NULL;
2392     xmlNodePtr child_node = NULL;
2393     const char *name = NULL;
2394     const char *title = NULL;
2395     const char *abstract = NULL;
2396     wmsLayerPtr lyr;
2397     struct _xmlAttr *attr;
2398 
2399     for (cur_node = node; cur_node; cur_node = cur_node->next)
2400       {
2401 	  if (cur_node->type == XML_ELEMENT_NODE)
2402 	    {
2403 		if (strcmp ((const char *) (cur_node->name), "Name") == 0)
2404 		  {
2405 		      child_node = cur_node->children;
2406 		      if (child_node != NULL)
2407 			{
2408 			    if (child_node->type == XML_TEXT_NODE)
2409 				name = (const char *) (child_node->content);
2410 			}
2411 		  }
2412 		if (strcmp ((const char *) (cur_node->name), "Title") == 0)
2413 		  {
2414 		      child_node = cur_node->children;
2415 		      if (child_node != NULL)
2416 			{
2417 			    if (child_node->type == XML_TEXT_NODE)
2418 				title = (const char *) (child_node->content);
2419 			}
2420 		  }
2421 		if (strcmp ((const char *) (cur_node->name), "Abstract") == 0)
2422 		  {
2423 		      child_node = cur_node->children;
2424 		      if (child_node != NULL)
2425 			{
2426 			    if (child_node->type == XML_TEXT_NODE)
2427 				abstract = (const char *) (child_node->content);
2428 			}
2429 		  }
2430 	    }
2431       }
2432     lyr = wmsAllocLayer (name, title, abstract, group);
2433     if (group->firstLayer == NULL)
2434 	group->firstLayer = lyr;
2435     if (group->lastLayer != NULL)
2436 	group->lastLayer->next = lyr;
2437     group->lastLayer = lyr;
2438 
2439     attr = properties;
2440     while (attr != NULL)
2441       {
2442 	  if (attr->name != NULL)
2443 	    {
2444 		xmlNodePtr text;
2445 		if (strcmp ((const char *) (attr->name), "queryable") == 0)
2446 		  {
2447 		      text = attr->children;
2448 		      if (text->type == XML_TEXT_NODE)
2449 			  lyr->Queryable =
2450 			      atoi ((const char *) (text->content));
2451 		  }
2452 		if (strcmp ((const char *) (attr->name), "opaque") == 0)
2453 		  {
2454 		      text = attr->children;
2455 		      if (text->type == XML_TEXT_NODE)
2456 			  lyr->Opaque = atoi ((const char *) (text->content));
2457 		  }
2458 	    }
2459 	  attr = attr->next;
2460       }
2461 
2462     for (cur_node = node; cur_node; cur_node = cur_node->next)
2463       {
2464 	  if (cur_node->type == XML_ELEMENT_NODE)
2465 	    {
2466 		if (strcmp ((const char *) (cur_node->name), "CRS") == 0
2467 		    || strcmp ((const char *) (cur_node->name), "SRS") == 0)
2468 		  {
2469 		      xmlNodePtr child_node = cur_node->children;
2470 		      if (child_node != NULL)
2471 			{
2472 			    if (child_node->type == XML_TEXT_NODE)
2473 			      {
2474 				  wmsCrsPtr crs;
2475 				  const char *crs_string =
2476 				      (const char *) (child_node->content);
2477 				  crs = wmsAllocCrs (crs_string);
2478 				  if (lyr->firstCrs == NULL)
2479 				      lyr->firstCrs = crs;
2480 				  if (lyr->lastCrs != NULL)
2481 				      lyr->lastCrs->next = crs;
2482 				  lyr->lastCrs = crs;
2483 			      }
2484 			}
2485 		  }
2486 		if (strcmp
2487 		    ((const char *) (cur_node->name),
2488 		     "EX_GeographicBoundingBox") == 0)
2489 		    parse_wms_EX_geoBBox (cur_node->children, lyr);
2490 		if (strcmp
2491 		    ((const char *) (cur_node->name), "LatLonBoundingBox") == 0)
2492 		    parse_wms_geoBBox (cur_node->properties, lyr);
2493 		if (strcmp ((const char *) (cur_node->name), "BoundingBox") ==
2494 		    0)
2495 		    parse_wms_BBox (cur_node->properties, lyr);
2496 		if (strcmp ((const char *) (cur_node->name), "Style") == 0)
2497 		    parse_wms_style (cur_node->children, lyr);
2498 		if (strcmp
2499 		    ((const char *) (cur_node->name),
2500 		     "MinScaleDenominator") == 0)
2501 		  {
2502 		      xmlNodePtr child_node = cur_node->children;
2503 		      if (child_node != NULL)
2504 			{
2505 			    if (child_node->type == XML_TEXT_NODE)
2506 			      {
2507 				  const char *str =
2508 				      (const char *) (child_node->content);
2509 				  lyr->MinScaleDenominator = atof (str);
2510 			      }
2511 			}
2512 		  }
2513 		if (strcmp
2514 		    ((const char *) (cur_node->name),
2515 		     "MaxScaleDenominator") == 0)
2516 		  {
2517 		      xmlNodePtr child_node = cur_node->children;
2518 		      if (child_node != NULL)
2519 			{
2520 			    if (child_node->type == XML_TEXT_NODE)
2521 			      {
2522 				  const char *str =
2523 				      (const char *) (child_node->content);
2524 				  lyr->MaxScaleDenominator = atof (str);
2525 			      }
2526 			}
2527 		  }
2528 		if (strcmp ((const char *) (cur_node->name), "Layer") == 0)
2529 		    parse_wms_layer_in_layer (cur_node->children,
2530 					      cur_node->properties, lyr,
2531 					      level + 1);
2532 	    }
2533       }
2534 }
2535 
2536 static void
parse_wms_layer(xmlNodePtr node,struct _xmlAttr * properties,wmsCapabilitiesPtr cap)2537 parse_wms_layer (xmlNodePtr node, struct _xmlAttr *properties,
2538 		 wmsCapabilitiesPtr cap)
2539 {
2540 /* parsing a WMS Layer definition */
2541     xmlNodePtr cur_node = NULL;
2542     xmlNodePtr child_node = NULL;
2543     const char *name = NULL;
2544     const char *title = NULL;
2545     const char *abstract = NULL;
2546     wmsLayerPtr lyr;
2547     struct _xmlAttr *attr;
2548 
2549     for (cur_node = node; cur_node; cur_node = cur_node->next)
2550       {
2551 	  if (cur_node->type == XML_ELEMENT_NODE)
2552 	    {
2553 		if (strcmp ((const char *) (cur_node->name), "Name") == 0)
2554 		  {
2555 		      child_node = cur_node->children;
2556 		      if (child_node != NULL)
2557 			{
2558 			    if (child_node->type == XML_TEXT_NODE)
2559 				name = (const char *) (child_node->content);
2560 			}
2561 		  }
2562 		if (strcmp ((const char *) (cur_node->name), "Title") == 0)
2563 		  {
2564 		      child_node = cur_node->children;
2565 		      if (child_node != NULL)
2566 			{
2567 			    if (child_node->type == XML_TEXT_NODE)
2568 				title = (const char *) (child_node->content);
2569 			}
2570 		  }
2571 		if (strcmp ((const char *) (cur_node->name), "Abstract") == 0)
2572 		  {
2573 		      child_node = cur_node->children;
2574 		      if (child_node != NULL)
2575 			{
2576 			    if (child_node->type == XML_TEXT_NODE)
2577 				abstract = (const char *) (child_node->content);
2578 			}
2579 		  }
2580 	    }
2581       }
2582     lyr = wmsAllocLayer (name, title, abstract, NULL);
2583     if (cap->firstLayer == NULL)
2584 	cap->firstLayer = lyr;
2585     if (cap->lastLayer != NULL)
2586 	cap->lastLayer->next = lyr;
2587     cap->lastLayer = lyr;
2588 
2589     attr = properties;
2590     while (attr != NULL)
2591       {
2592 	  if (attr->name != NULL)
2593 	    {
2594 		xmlNodePtr text;
2595 		if (strcmp ((const char *) (attr->name), "queryable") == 0)
2596 		  {
2597 		      text = attr->children;
2598 		      if (text->type == XML_TEXT_NODE)
2599 			  lyr->Queryable =
2600 			      atoi ((const char *) (text->content));
2601 		  }
2602 		if (strcmp ((const char *) (attr->name), "opaque") == 0)
2603 		  {
2604 		      text = attr->children;
2605 		      if (text->type == XML_TEXT_NODE)
2606 			  lyr->Opaque = atoi ((const char *) (text->content));
2607 		  }
2608 	    }
2609 	  attr = attr->next;
2610       }
2611 
2612     for (cur_node = node; cur_node; cur_node = cur_node->next)
2613       {
2614 	  if (cur_node->type == XML_ELEMENT_NODE)
2615 	    {
2616 		if (strcmp ((const char *) (cur_node->name), "CRS") == 0
2617 		    || strcmp ((const char *) (cur_node->name), "SRS") == 0)
2618 		  {
2619 		      xmlNodePtr child_node = cur_node->children;
2620 		      if (child_node != NULL)
2621 			{
2622 			    if (child_node->type == XML_TEXT_NODE)
2623 			      {
2624 				  wmsCrsPtr crs;
2625 				  const char *crs_string =
2626 				      (const char *) (child_node->content);
2627 				  crs = wmsAllocCrs (crs_string);
2628 				  if (lyr->firstCrs == NULL)
2629 				      lyr->firstCrs = crs;
2630 				  if (lyr->lastCrs != NULL)
2631 				      lyr->lastCrs->next = crs;
2632 				  lyr->lastCrs = crs;
2633 			      }
2634 			}
2635 		  }
2636 		if (strcmp
2637 		    ((const char *) (cur_node->name),
2638 		     "EX_GeographicBoundingBox") == 0)
2639 		    parse_wms_EX_geoBBox (cur_node->children, lyr);
2640 		if (strcmp
2641 		    ((const char *) (cur_node->name), "LatLonBoundingBox") == 0)
2642 		    parse_wms_geoBBox (cur_node->properties, lyr);
2643 		if (strcmp ((const char *) (cur_node->name), "BoundingBox") ==
2644 		    0)
2645 		    parse_wms_BBox (cur_node->properties, lyr);
2646 		if (strcmp ((const char *) (cur_node->name), "Style") == 0)
2647 		    parse_wms_style (cur_node->children, lyr);
2648 		if (strcmp
2649 		    ((const char *) (cur_node->name),
2650 		     "MinScaleDenominator") == 0)
2651 		  {
2652 		      xmlNodePtr child_node = cur_node->children;
2653 		      if (child_node != NULL)
2654 			{
2655 			    if (child_node->type == XML_TEXT_NODE)
2656 			      {
2657 				  const char *str =
2658 				      (const char *) (child_node->content);
2659 				  lyr->MinScaleDenominator = atof (str);
2660 			      }
2661 			}
2662 		  }
2663 		if (strcmp
2664 		    ((const char *) (cur_node->name),
2665 		     "MaxScaleDenominator") == 0)
2666 		  {
2667 		      xmlNodePtr child_node = cur_node->children;
2668 		      if (child_node != NULL)
2669 			{
2670 			    if (child_node->type == XML_TEXT_NODE)
2671 			      {
2672 				  const char *str =
2673 				      (const char *) (child_node->content);
2674 				  lyr->MaxScaleDenominator = atof (str);
2675 			      }
2676 			}
2677 		  }
2678 		if (strcmp ((const char *) (cur_node->name), "Layer") == 0)
2679 		    parse_wms_layer_in_layer (cur_node->children,
2680 					      cur_node->properties, lyr, 0);
2681 	    }
2682       }
2683 }
2684 
2685 static void
parse_wms_contact_person(xmlNodePtr node,const char ** contact_person,const char ** contact_organization)2686 parse_wms_contact_person (xmlNodePtr node, const char **contact_person,
2687 			  const char **contact_organization)
2688 {
2689 /* parsing a WMS ContactPersonPrimary definition */
2690     xmlNodePtr cur_node = NULL;
2691     xmlNodePtr child_node = NULL;
2692 
2693     for (cur_node = node; cur_node; cur_node = cur_node->next)
2694       {
2695 	  if (cur_node->type == XML_ELEMENT_NODE)
2696 	    {
2697 		if (strcmp
2698 		    ((const char *) (cur_node->name),
2699 		     "ContactOrganization") == 0)
2700 		  {
2701 		      child_node = cur_node->children;
2702 		      if (child_node != NULL)
2703 			{
2704 			    if (child_node->type == XML_TEXT_NODE)
2705 				*contact_organization =
2706 				    (const char *) (child_node->content);
2707 			}
2708 		  }
2709 		if (strcmp ((const char *) (cur_node->name), "ContactPerson") ==
2710 		    0)
2711 		  {
2712 		      child_node = cur_node->children;
2713 		      if (child_node != NULL)
2714 			{
2715 			    if (child_node->type == XML_TEXT_NODE)
2716 				*contact_person =
2717 				    (const char *) (child_node->content);
2718 			}
2719 		  }
2720 	    }
2721       }
2722 }
2723 
2724 static void
parse_wms_contact_address(xmlNodePtr node,const char ** postal_address,const char ** city,const char ** state_province,const char ** post_code,const char ** country)2725 parse_wms_contact_address (xmlNodePtr node, const char **postal_address,
2726 			   const char **city, const char **state_province,
2727 			   const char **post_code, const char **country)
2728 {
2729 /* parsing a WMS ContactAddress definition */
2730     xmlNodePtr cur_node = NULL;
2731     xmlNodePtr child_node = NULL;
2732 
2733     for (cur_node = node; cur_node; cur_node = cur_node->next)
2734       {
2735 	  if (cur_node->type == XML_ELEMENT_NODE)
2736 	    {
2737 		if (strcmp ((const char *) (cur_node->name), "Address") == 0)
2738 		  {
2739 		      child_node = cur_node->children;
2740 		      if (child_node != NULL)
2741 			{
2742 			    if (child_node->type == XML_TEXT_NODE)
2743 				*postal_address =
2744 				    (const char *) (child_node->content);
2745 			}
2746 		  }
2747 		if (strcmp ((const char *) (cur_node->name), "City") == 0)
2748 		  {
2749 		      child_node = cur_node->children;
2750 		      if (child_node != NULL)
2751 			{
2752 			    if (child_node->type == XML_TEXT_NODE)
2753 				*city = (const char *) (child_node->content);
2754 			}
2755 		  }
2756 		if (strcmp ((const char *) (cur_node->name), "StateOrProvince")
2757 		    == 0)
2758 		  {
2759 		      child_node = cur_node->children;
2760 		      if (child_node != NULL)
2761 			{
2762 			    if (child_node->type == XML_TEXT_NODE)
2763 				*state_province =
2764 				    (const char *) (child_node->content);
2765 			}
2766 		  }
2767 		if (strcmp ((const char *) (cur_node->name), "PostCode") == 0)
2768 		  {
2769 		      child_node = cur_node->children;
2770 		      if (child_node != NULL)
2771 			{
2772 			    if (child_node->type == XML_TEXT_NODE)
2773 				*post_code =
2774 				    (const char *) (child_node->content);
2775 			}
2776 		  }
2777 		if (strcmp ((const char *) (cur_node->name), "Country") == 0)
2778 		  {
2779 		      child_node = cur_node->children;
2780 		      if (child_node != NULL)
2781 			{
2782 			    if (child_node->type == XML_TEXT_NODE)
2783 				*country = (const char *) (child_node->content);
2784 			}
2785 		  }
2786 	    }
2787       }
2788 }
2789 
2790 static void
parse_wms_contact_information(xmlNodePtr node,const char ** contact_person,const char ** contact_organization,const char ** contact_position,const char ** postal_address,const char ** city,const char ** state_province,const char ** post_code,const char ** country,const char ** voice_telephone,const char ** fax_telephone,const char ** email_address)2791 parse_wms_contact_information (xmlNodePtr node, const char **contact_person,
2792 			       const char **contact_organization,
2793 			       const char **contact_position,
2794 			       const char **postal_address, const char **city,
2795 			       const char **state_province,
2796 			       const char **post_code, const char **country,
2797 			       const char **voice_telephone,
2798 			       const char **fax_telephone,
2799 			       const char **email_address)
2800 {
2801 /* parsing a WMS ContactInformation definition */
2802     xmlNodePtr cur_node = NULL;
2803     xmlNodePtr child_node = NULL;
2804 
2805     for (cur_node = node; cur_node; cur_node = cur_node->next)
2806       {
2807 	  if (cur_node->type == XML_ELEMENT_NODE)
2808 	    {
2809 		if (strcmp ((const char *) (cur_node->name), "ContactPosition")
2810 		    == 0)
2811 		  {
2812 		      child_node = cur_node->children;
2813 		      if (child_node != NULL)
2814 			{
2815 			    if (child_node->type == XML_TEXT_NODE)
2816 				*contact_position =
2817 				    (const char *) (child_node->content);
2818 			}
2819 		  }
2820 		if (strcmp
2821 		    ((const char *) (cur_node->name),
2822 		     "ContactPersonPrimary") == 0)
2823 		    parse_wms_contact_person (cur_node->children,
2824 					      contact_person,
2825 					      contact_organization);
2826 		if (strcmp ((const char *) (cur_node->name), "ContactAddress")
2827 		    == 0)
2828 		    parse_wms_contact_address (cur_node->children,
2829 					       postal_address, city,
2830 					       state_province, post_code,
2831 					       country);
2832 		if (strcmp
2833 		    ((const char *) (cur_node->name),
2834 		     "ContactVoiceTelephone") == 0)
2835 		  {
2836 		      child_node = cur_node->children;
2837 		      if (child_node != NULL)
2838 			{
2839 			    if (child_node->type == XML_TEXT_NODE)
2840 				*voice_telephone =
2841 				    (const char *) (child_node->content);
2842 			}
2843 		  }
2844 		if (strcmp
2845 		    ((const char *) (cur_node->name),
2846 		     "ContactFacsimileTelephone") == 0)
2847 		  {
2848 		      child_node = cur_node->children;
2849 		      if (child_node != NULL)
2850 			{
2851 			    if (child_node->type == XML_TEXT_NODE)
2852 				*fax_telephone =
2853 				    (const char *) (child_node->content);
2854 			}
2855 		  }
2856 		if (strcmp
2857 		    ((const char *) (cur_node->name),
2858 		     "ContactElectronicMailAddress") == 0)
2859 		  {
2860 		      child_node = cur_node->children;
2861 		      if (child_node != NULL)
2862 			{
2863 			    if (child_node->type == XML_TEXT_NODE)
2864 				*email_address =
2865 				    (const char *) (child_node->content);
2866 			}
2867 		  }
2868 	    }
2869       }
2870 }
2871 
2872 static void
parse_wms_service(xmlNodePtr node,wmsCapabilitiesPtr cap)2873 parse_wms_service (xmlNodePtr node, wmsCapabilitiesPtr cap)
2874 {
2875 /* parsing a WMS Service definition */
2876     xmlNodePtr cur_node = NULL;
2877     xmlNodePtr child_node = NULL;
2878     const char *name = NULL;
2879     const char *title = NULL;
2880     const char *abstract = NULL;
2881     const char *contact_person = NULL;
2882     const char *contact_organization = NULL;
2883     const char *contact_position = NULL;
2884     const char *postal_address = NULL;
2885     const char *city = NULL;
2886     const char *state_province = NULL;
2887     const char *post_code = NULL;
2888     const char *country = NULL;
2889     const char *voice_telephone = NULL;
2890     const char *fax_telephone = NULL;
2891     const char *email_address = NULL;
2892     const char *fees = NULL;
2893     const char *access_constraints = NULL;
2894     int layer_limit = -1;
2895     int maxWidth = -1;
2896     int maxHeight = -1;
2897     int len;
2898 
2899     for (cur_node = node; cur_node; cur_node = cur_node->next)
2900       {
2901 	  if (cur_node->type == XML_ELEMENT_NODE)
2902 	    {
2903 		if (strcmp ((const char *) (cur_node->name), "Name") == 0)
2904 		  {
2905 		      child_node = cur_node->children;
2906 		      if (child_node != NULL)
2907 			{
2908 			    if (child_node->type == XML_TEXT_NODE)
2909 				name = (const char *) (child_node->content);
2910 			}
2911 		  }
2912 		if (strcmp ((const char *) (cur_node->name), "Title") == 0)
2913 		  {
2914 		      child_node = cur_node->children;
2915 		      if (child_node != NULL)
2916 			{
2917 			    if (child_node->type == XML_TEXT_NODE)
2918 				title = (const char *) (child_node->content);
2919 			}
2920 		  }
2921 		if (strcmp ((const char *) (cur_node->name), "Abstract") == 0)
2922 		  {
2923 		      child_node = cur_node->children;
2924 		      if (child_node != NULL)
2925 			{
2926 			    if (child_node->type == XML_TEXT_NODE)
2927 				abstract = (const char *) (child_node->content);
2928 			}
2929 		  }
2930 		if (strcmp
2931 		    ((const char *) (cur_node->name),
2932 		     "ContactInformation") == 0)
2933 		    parse_wms_contact_information (cur_node->children,
2934 						   &contact_person,
2935 						   &contact_organization,
2936 						   &contact_position,
2937 						   &postal_address, &city,
2938 						   &state_province, &post_code,
2939 						   &country, &voice_telephone,
2940 						   &fax_telephone,
2941 						   &email_address);
2942 		if (strcmp ((const char *) (cur_node->name), "Fees") == 0)
2943 		  {
2944 		      child_node = cur_node->children;
2945 		      if (child_node != NULL)
2946 			{
2947 			    if (child_node->type == XML_TEXT_NODE)
2948 				fees = (const char *) (child_node->content);
2949 			}
2950 		  }
2951 		if (strcmp
2952 		    ((const char *) (cur_node->name), "AccessConstraints") == 0)
2953 		  {
2954 		      child_node = cur_node->children;
2955 		      if (child_node != NULL)
2956 			{
2957 			    if (child_node->type == XML_TEXT_NODE)
2958 				access_constraints =
2959 				    (const char *) (child_node->content);
2960 			}
2961 		  }
2962 		if (strcmp ((const char *) (cur_node->name), "LayerLimit") == 0)
2963 		  {
2964 		      child_node = cur_node->children;
2965 		      if (child_node != NULL)
2966 			{
2967 			    if (child_node->type == XML_TEXT_NODE)
2968 				layer_limit =
2969 				    atoi ((const char *) (child_node->content));
2970 			}
2971 		  }
2972 		if (strcmp ((const char *) (cur_node->name), "MaxWidth") == 0)
2973 		  {
2974 		      child_node = cur_node->children;
2975 		      if (child_node != NULL)
2976 			{
2977 			    if (child_node->type == XML_TEXT_NODE)
2978 				maxWidth =
2979 				    atoi ((const char *) (child_node->content));
2980 			}
2981 		  }
2982 		if (strcmp ((const char *) (cur_node->name), "MaxHeight") == 0)
2983 		  {
2984 		      child_node = cur_node->children;
2985 		      if (child_node != NULL)
2986 			{
2987 			    if (child_node->type == XML_TEXT_NODE)
2988 				maxHeight =
2989 				    atoi ((const char *) (child_node->content));
2990 			}
2991 		  }
2992 	    }
2993       }
2994 
2995     if (cap->Name != NULL)
2996       {
2997 	  free (cap->Name);
2998 	  cap->Name = NULL;
2999       }
3000     if (name != NULL)
3001       {
3002 	  len = strlen (name);
3003 	  cap->Name = malloc (len + 1);
3004 	  strcpy (cap->Name, name);
3005       }
3006     if (cap->Title != NULL)
3007       {
3008 	  free (cap->Title);
3009 	  cap->Title = NULL;
3010       }
3011     if (title != NULL)
3012       {
3013 	  len = strlen (title);
3014 	  cap->Title = malloc (len + 1);
3015 	  strcpy (cap->Title, title);
3016       }
3017     if (cap->Abstract != NULL)
3018       {
3019 	  free (cap->Abstract);
3020 	  cap->Abstract = NULL;
3021       }
3022     if (abstract != NULL)
3023       {
3024 	  len = strlen (abstract);
3025 	  cap->Abstract = malloc (len + 1);
3026 	  strcpy (cap->Abstract, abstract);
3027       }
3028     if (contact_person != NULL)
3029       {
3030 	  len = strlen (contact_person);
3031 	  cap->ContactPerson = malloc (len + 1);
3032 	  strcpy (cap->ContactPerson, contact_person);
3033       }
3034     if (contact_organization != NULL)
3035       {
3036 	  len = strlen (contact_organization);
3037 	  cap->ContactOrganization = malloc (len + 1);
3038 	  strcpy (cap->ContactOrganization, contact_organization);
3039       }
3040     if (contact_position != NULL)
3041       {
3042 	  len = strlen (contact_position);
3043 	  cap->ContactPosition = malloc (len + 1);
3044 	  strcpy (cap->ContactPosition, contact_position);
3045       }
3046     if (postal_address != NULL)
3047       {
3048 	  len = strlen (postal_address);
3049 	  cap->PostalAddress = malloc (len + 1);
3050 	  strcpy (cap->PostalAddress, postal_address);
3051       }
3052     if (city != NULL)
3053       {
3054 	  len = strlen (city);
3055 	  cap->City = malloc (len + 1);
3056 	  strcpy (cap->City, city);
3057       }
3058     if (state_province != NULL)
3059       {
3060 	  len = strlen (state_province);
3061 	  cap->StateProvince = malloc (len + 1);
3062 	  strcpy (cap->StateProvince, state_province);
3063       }
3064     if (post_code != NULL)
3065       {
3066 	  len = strlen (post_code);
3067 	  cap->PostCode = malloc (len + 1);
3068 	  strcpy (cap->PostCode, post_code);
3069       }
3070     if (country != NULL)
3071       {
3072 	  len = strlen (country);
3073 	  cap->Country = malloc (len + 1);
3074 	  strcpy (cap->Country, country);
3075       }
3076     if (voice_telephone != NULL)
3077       {
3078 	  len = strlen (voice_telephone);
3079 	  cap->VoiceTelephone = malloc (len + 1);
3080 	  strcpy (cap->VoiceTelephone, voice_telephone);
3081       }
3082     if (fax_telephone != NULL)
3083       {
3084 	  len = strlen (fax_telephone);
3085 	  cap->FaxTelephone = malloc (len + 1);
3086 	  strcpy (cap->FaxTelephone, fax_telephone);
3087       }
3088     if (email_address != NULL)
3089       {
3090 	  len = strlen (email_address);
3091 	  cap->EMailAddress = malloc (len + 1);
3092 	  strcpy (cap->EMailAddress, email_address);
3093       }
3094     if (fees != NULL)
3095       {
3096 	  len = strlen (fees);
3097 	  cap->Fees = malloc (len + 1);
3098 	  strcpy (cap->Fees, fees);
3099       }
3100     if (access_constraints != NULL)
3101       {
3102 	  len = strlen (access_constraints);
3103 	  cap->AccessConstraints = malloc (len + 1);
3104 	  strcpy (cap->AccessConstraints, access_constraints);
3105       }
3106     if (layer_limit > 0)
3107 	cap->LayerLimit = layer_limit;
3108     if (maxWidth > 0)
3109 	cap->MaxWidth = maxWidth;
3110     if (maxHeight > 0)
3111 	cap->MaxHeight = maxHeight;
3112 }
3113 
3114 static void
parse_wms_GetMap_HTTP_Get(xmlNodePtr node,wmsCapabilitiesPtr cap)3115 parse_wms_GetMap_HTTP_Get (xmlNodePtr node, wmsCapabilitiesPtr cap)
3116 {
3117 /* recursively parsing the GetCapabilities/Capability/Request/GetMap/DCPType/HTTP/Get node */
3118     xmlNodePtr cur_node = NULL;
3119     int len;
3120     const char *p;
3121 
3122     for (cur_node = node; cur_node; cur_node = cur_node->next)
3123       {
3124 	  if (cur_node->type == XML_ELEMENT_NODE)
3125 	    {
3126 		if (strcmp ((const char *) (cur_node->name), "OnlineResource")
3127 		    == 0)
3128 		  {
3129 		      struct _xmlAttr *attr = cur_node->properties;
3130 		      while (attr != NULL)
3131 			{
3132 			    if (attr->name != NULL)
3133 			      {
3134 				  if (strcmp
3135 				      ((const char *) (attr->name),
3136 				       "href") == 0)
3137 				    {
3138 					xmlNodePtr text = attr->children;
3139 					if (text->type == XML_TEXT_NODE)
3140 					  {
3141 					      if (cap->GetMapURLGet != NULL)
3142 						{
3143 						    free (cap->GetMapURLGet);
3144 						    cap->GetMapURLGet = NULL;
3145 						}
3146 					      p = (const char
3147 						   *) (text->content);
3148 					      len = strlen (p);
3149 					      cap->GetMapURLGet =
3150 						  malloc (len + 1);
3151 					      strcpy (cap->GetMapURLGet, p);
3152 					  }
3153 				    }
3154 			      }
3155 			    attr = attr->next;
3156 			}
3157 		  }
3158 	    }
3159       }
3160 }
3161 
3162 static void
parse_wms_GetMap_HTTP_Post(xmlNodePtr node,wmsCapabilitiesPtr cap)3163 parse_wms_GetMap_HTTP_Post (xmlNodePtr node, wmsCapabilitiesPtr cap)
3164 {
3165 /* recursively parsing the GetCapabilities/Capability/Request/GetMap/DCPType/HTTP/Post node */
3166     xmlNodePtr cur_node = NULL;
3167     int len;
3168     const char *p;
3169 
3170     for (cur_node = node; cur_node; cur_node = cur_node->next)
3171       {
3172 	  if (cur_node->type == XML_ELEMENT_NODE)
3173 	    {
3174 		if (strcmp ((const char *) (cur_node->name), "OnlineResource")
3175 		    == 0)
3176 		  {
3177 		      struct _xmlAttr *attr = cur_node->properties;
3178 		      while (attr != NULL)
3179 			{
3180 			    if (attr->name != NULL)
3181 			      {
3182 				  if (strcmp
3183 				      ((const char *) (attr->name),
3184 				       "href") == 0)
3185 				    {
3186 					xmlNodePtr text = attr->children;
3187 					if (text->type == XML_TEXT_NODE)
3188 					  {
3189 					      if (cap->GetMapURLPost != NULL)
3190 						{
3191 						    free (cap->GetMapURLPost);
3192 						    cap->GetMapURLPost = NULL;
3193 						}
3194 					      p = (const char
3195 						   *) (text->content);
3196 					      len = strlen (p);
3197 					      cap->GetMapURLPost =
3198 						  malloc (len + 1);
3199 					      strcpy (cap->GetMapURLPost, p);
3200 					  }
3201 				    }
3202 			      }
3203 			    attr = attr->next;
3204 			}
3205 		  }
3206 	    }
3207       }
3208 }
3209 
3210 static void
parse_wms_GetTileService_HTTP_Get(xmlNodePtr node,wmsCapabilitiesPtr cap)3211 parse_wms_GetTileService_HTTP_Get (xmlNodePtr node, wmsCapabilitiesPtr cap)
3212 {
3213 /* recursively parsing the GetCapabilities/Capability/Request/GetTileService/DCPType/HTTP/Get node */
3214     xmlNodePtr cur_node = NULL;
3215     int len;
3216     const char *p;
3217 
3218     for (cur_node = node; cur_node; cur_node = cur_node->next)
3219       {
3220 	  if (cur_node->type == XML_ELEMENT_NODE)
3221 	    {
3222 		if (strcmp ((const char *) (cur_node->name), "OnlineResource")
3223 		    == 0)
3224 		  {
3225 		      struct _xmlAttr *attr = cur_node->properties;
3226 		      while (attr != NULL)
3227 			{
3228 			    if (attr->name != NULL)
3229 			      {
3230 				  if (strcmp
3231 				      ((const char *) (attr->name),
3232 				       "href") == 0)
3233 				    {
3234 					xmlNodePtr text = attr->children;
3235 					if (text->type == XML_TEXT_NODE)
3236 					  {
3237 					      if (cap->GetTileServiceURLGet !=
3238 						  NULL)
3239 						{
3240 						    free (cap->
3241 							  GetTileServiceURLGet);
3242 						    cap->GetMapURLGet = NULL;
3243 						}
3244 					      p = (const char
3245 						   *) (text->content);
3246 					      len = strlen (p);
3247 					      cap->GetTileServiceURLGet =
3248 						  malloc (len + 1);
3249 					      strcpy (cap->GetTileServiceURLGet,
3250 						      p);
3251 					  }
3252 				    }
3253 			      }
3254 			    attr = attr->next;
3255 			}
3256 		  }
3257 	    }
3258       }
3259 }
3260 
3261 static void
parse_wms_GetTileService_HTTP_Post(xmlNodePtr node,wmsCapabilitiesPtr cap)3262 parse_wms_GetTileService_HTTP_Post (xmlNodePtr node, wmsCapabilitiesPtr cap)
3263 {
3264 /* recursively parsing the GetCapabilities/Capability/Request/GetTileService/DCPType/HTTP/Post node */
3265     xmlNodePtr cur_node = NULL;
3266     int len;
3267     const char *p;
3268 
3269     for (cur_node = node; cur_node; cur_node = cur_node->next)
3270       {
3271 	  if (cur_node->type == XML_ELEMENT_NODE)
3272 	    {
3273 		if (strcmp ((const char *) (cur_node->name), "OnlineResource")
3274 		    == 0)
3275 		  {
3276 		      struct _xmlAttr *attr = cur_node->properties;
3277 		      while (attr != NULL)
3278 			{
3279 			    if (attr->name != NULL)
3280 			      {
3281 				  if (strcmp
3282 				      ((const char *) (attr->name),
3283 				       "href") == 0)
3284 				    {
3285 					xmlNodePtr text = attr->children;
3286 					if (text->type == XML_TEXT_NODE)
3287 					  {
3288 					      if (cap->GetTileServiceURLPost !=
3289 						  NULL)
3290 						{
3291 						    free (cap->
3292 							  GetTileServiceURLPost);
3293 						    cap->GetTileServiceURLPost =
3294 							NULL;
3295 						}
3296 					      p = (const char
3297 						   *) (text->content);
3298 					      len = strlen (p);
3299 					      cap->GetTileServiceURLPost =
3300 						  malloc (len + 1);
3301 					      strcpy
3302 						  (cap->GetTileServiceURLPost,
3303 						   p);
3304 					  }
3305 				    }
3306 			      }
3307 			    attr = attr->next;
3308 			}
3309 		  }
3310 	    }
3311       }
3312 }
3313 
3314 static void
parse_wms_GetInfo_HTTP_Get(xmlNodePtr node,wmsCapabilitiesPtr cap)3315 parse_wms_GetInfo_HTTP_Get (xmlNodePtr node, wmsCapabilitiesPtr cap)
3316 {
3317 /* recursively parsing the GetCapabilities/Capability/Request/GetFeatureInfo/DCPType/HTTP/Get node */
3318     xmlNodePtr cur_node = NULL;
3319     int len;
3320     const char *p;
3321 
3322     for (cur_node = node; cur_node; cur_node = cur_node->next)
3323       {
3324 	  if (cur_node->type == XML_ELEMENT_NODE)
3325 	    {
3326 		if (strcmp ((const char *) (cur_node->name), "OnlineResource")
3327 		    == 0)
3328 		  {
3329 		      struct _xmlAttr *attr = cur_node->properties;
3330 		      while (attr != NULL)
3331 			{
3332 			    if (attr->name != NULL)
3333 			      {
3334 				  if (strcmp
3335 				      ((const char *) (attr->name),
3336 				       "href") == 0)
3337 				    {
3338 					xmlNodePtr text = attr->children;
3339 					if (text->type == XML_TEXT_NODE)
3340 					  {
3341 					      if (cap->GetFeatureInfoURLGet !=
3342 						  NULL)
3343 						{
3344 						    free (cap->GetFeatureInfoURLGet);
3345 						    cap->GetFeatureInfoURLGet =
3346 							NULL;
3347 						}
3348 					      p = (const char
3349 						   *) (text->content);
3350 					      len = strlen (p);
3351 					      cap->GetFeatureInfoURLGet =
3352 						  malloc (len + 1);
3353 					      strcpy (cap->GetFeatureInfoURLGet,
3354 						      p);
3355 					  }
3356 				    }
3357 			      }
3358 			    attr = attr->next;
3359 			}
3360 		  }
3361 	    }
3362       }
3363 }
3364 
3365 static void
parse_wms_GetInfo_HTTP_Post(xmlNodePtr node,wmsCapabilitiesPtr cap)3366 parse_wms_GetInfo_HTTP_Post (xmlNodePtr node, wmsCapabilitiesPtr cap)
3367 {
3368 /* recursively parsing the GetCapabilities/Capability/Request/GetFeatureInfo/DCPType/HTTP/Post node */
3369     xmlNodePtr cur_node = NULL;
3370     int len;
3371     const char *p;
3372 
3373     for (cur_node = node; cur_node; cur_node = cur_node->next)
3374       {
3375 	  if (cur_node->type == XML_ELEMENT_NODE)
3376 	    {
3377 		if (strcmp ((const char *) (cur_node->name), "OnlineResource")
3378 		    == 0)
3379 		  {
3380 		      struct _xmlAttr *attr = cur_node->properties;
3381 		      while (attr != NULL)
3382 			{
3383 			    if (attr->name != NULL)
3384 			      {
3385 				  if (strcmp
3386 				      ((const char *) (attr->name),
3387 				       "href") == 0)
3388 				    {
3389 					xmlNodePtr text = attr->children;
3390 					if (text->type == XML_TEXT_NODE)
3391 					  {
3392 					      if (cap->GetFeatureInfoURLPost !=
3393 						  NULL)
3394 						{
3395 						    free (cap->GetFeatureInfoURLPost);
3396 						    cap->GetFeatureInfoURLPost =
3397 							NULL;
3398 						}
3399 					      p = (const char
3400 						   *) (text->content);
3401 					      len = strlen (p);
3402 					      cap->GetFeatureInfoURLPost =
3403 						  malloc (len + 1);
3404 					      strcpy
3405 						  (cap->GetFeatureInfoURLPost,
3406 						   p);
3407 					  }
3408 				    }
3409 			      }
3410 			    attr = attr->next;
3411 			}
3412 		  }
3413 	    }
3414       }
3415 }
3416 
3417 static void
parse_wms_GetMap_HTTP(xmlNodePtr node,wmsCapabilitiesPtr cap)3418 parse_wms_GetMap_HTTP (xmlNodePtr node, wmsCapabilitiesPtr cap)
3419 {
3420 /* recursively parsing the GetCapabilities/Capability/Request/GetMap/DCPType node */
3421     xmlNodePtr cur_node = NULL;
3422 
3423     for (cur_node = node; cur_node; cur_node = cur_node->next)
3424       {
3425 	  if (cur_node->type == XML_ELEMENT_NODE)
3426 	    {
3427 		if (strcmp ((const char *) (cur_node->name), "Get") == 0)
3428 		    parse_wms_GetMap_HTTP_Get (cur_node->children, cap);
3429 		if (strcmp ((const char *) (cur_node->name), "Post") == 0)
3430 		    parse_wms_GetMap_HTTP_Post (cur_node->children, cap);
3431 	    }
3432       }
3433 }
3434 
3435 static void
parse_wms_GetTileService_HTTP(xmlNodePtr node,wmsCapabilitiesPtr cap)3436 parse_wms_GetTileService_HTTP (xmlNodePtr node, wmsCapabilitiesPtr cap)
3437 {
3438 /* recursively parsing the GetCapabilities/Capability/Request/GetTileService/DCPType node */
3439     xmlNodePtr cur_node = NULL;
3440 
3441     for (cur_node = node; cur_node; cur_node = cur_node->next)
3442       {
3443 	  if (cur_node->type == XML_ELEMENT_NODE)
3444 	    {
3445 		if (strcmp ((const char *) (cur_node->name), "Get") == 0)
3446 		    parse_wms_GetTileService_HTTP_Get (cur_node->children, cap);
3447 		if (strcmp ((const char *) (cur_node->name), "Post") == 0)
3448 		    parse_wms_GetTileService_HTTP_Post (cur_node->children,
3449 							cap);
3450 	    }
3451       }
3452 }
3453 
3454 static void
parse_wms_GetInfo_HTTP(xmlNodePtr node,wmsCapabilitiesPtr cap)3455 parse_wms_GetInfo_HTTP (xmlNodePtr node, wmsCapabilitiesPtr cap)
3456 {
3457 /* recursively parsing the GetCapabilities/Capability/Request/GetFeatureInfo/DCPType node */
3458     xmlNodePtr cur_node = NULL;
3459 
3460     for (cur_node = node; cur_node; cur_node = cur_node->next)
3461       {
3462 	  if (cur_node->type == XML_ELEMENT_NODE)
3463 	    {
3464 		if (strcmp ((const char *) (cur_node->name), "Get") == 0)
3465 		    parse_wms_GetInfo_HTTP_Get (cur_node->children, cap);
3466 		if (strcmp ((const char *) (cur_node->name), "Post") == 0)
3467 		    parse_wms_GetInfo_HTTP_Post (cur_node->children, cap);
3468 	    }
3469       }
3470 }
3471 
3472 static void
parse_wms_GetMap_DCPType(xmlNodePtr node,wmsCapabilitiesPtr cap)3473 parse_wms_GetMap_DCPType (xmlNodePtr node, wmsCapabilitiesPtr cap)
3474 {
3475 /* recursively parsing the GetCapabilities/Capability/Request/GetMap/DCPType node */
3476     xmlNodePtr cur_node = NULL;
3477 
3478     for (cur_node = node; cur_node; cur_node = cur_node->next)
3479       {
3480 	  if (cur_node->type == XML_ELEMENT_NODE)
3481 	    {
3482 		if (strcmp ((const char *) (cur_node->name), "HTTP") == 0)
3483 		    parse_wms_GetMap_HTTP (cur_node->children, cap);
3484 	    }
3485       }
3486 }
3487 
3488 static void
parse_wms_GetInfo_DCPType(xmlNodePtr node,wmsCapabilitiesPtr cap)3489 parse_wms_GetInfo_DCPType (xmlNodePtr node, wmsCapabilitiesPtr cap)
3490 {
3491 /* recursively parsing the GetCapabilities/Capability/Request/GetFeatureInfo/DCPType node */
3492     xmlNodePtr cur_node = NULL;
3493 
3494     for (cur_node = node; cur_node; cur_node = cur_node->next)
3495       {
3496 	  if (cur_node->type == XML_ELEMENT_NODE)
3497 	    {
3498 		if (strcmp ((const char *) (cur_node->name), "HTTP") == 0)
3499 		    parse_wms_GetInfo_HTTP (cur_node->children, cap);
3500 	    }
3501       }
3502 }
3503 
3504 static void
parse_wms_GetTileService_DCPType(xmlNodePtr node,wmsCapabilitiesPtr cap)3505 parse_wms_GetTileService_DCPType (xmlNodePtr node, wmsCapabilitiesPtr cap)
3506 {
3507 /* recursively parsing the GetCapabilities/Capability/Request/GetTileService/DCPType node */
3508     xmlNodePtr cur_node = NULL;
3509 
3510     for (cur_node = node; cur_node; cur_node = cur_node->next)
3511       {
3512 	  if (cur_node->type == XML_ELEMENT_NODE)
3513 	    {
3514 		if (strcmp ((const char *) (cur_node->name), "HTTP") == 0)
3515 		    parse_wms_GetTileService_HTTP (cur_node->children, cap);
3516 	    }
3517       }
3518 }
3519 
3520 static void
parse_wms_getMap(xmlNodePtr node,wmsCapabilitiesPtr cap)3521 parse_wms_getMap (xmlNodePtr node, wmsCapabilitiesPtr cap)
3522 {
3523 /* recursively parsing the GetCapabilities/Capability/Request/GetMap node */
3524     xmlNodePtr cur_node = NULL;
3525 
3526     for (cur_node = node; cur_node; cur_node = cur_node->next)
3527       {
3528 	  if (cur_node->type == XML_ELEMENT_NODE)
3529 	    {
3530 		if (strcmp ((const char *) (cur_node->name), "Format") == 0)
3531 		  {
3532 		      xmlNodePtr child_node = cur_node->children;
3533 		      if (child_node != NULL)
3534 			{
3535 			    if (child_node->type == XML_TEXT_NODE)
3536 			      {
3537 				  wmsFormatPtr fmt;
3538 				  const char *format =
3539 				      (const char *) (child_node->content);
3540 				  fmt = wmsAllocFormat (format);
3541 				  if (cap->firstFormat == NULL)
3542 				      cap->firstFormat = fmt;
3543 				  if (cap->lastFormat != NULL)
3544 				      cap->lastFormat->next = fmt;
3545 				  cap->lastFormat = fmt;
3546 			      }
3547 			}
3548 		  }
3549 		if (strcmp ((const char *) (cur_node->name), "DCPType") == 0)
3550 		    parse_wms_GetMap_DCPType (cur_node->children, cap);
3551 	    }
3552       }
3553 }
3554 
3555 static void
parse_wms_getInfo(xmlNodePtr node,wmsCapabilitiesPtr cap)3556 parse_wms_getInfo (xmlNodePtr node, wmsCapabilitiesPtr cap)
3557 {
3558 /* recursively parsing the GetCapabilities/Capability/Request/GetFeatureInfo node */
3559     xmlNodePtr cur_node = NULL;
3560 
3561     for (cur_node = node; cur_node; cur_node = cur_node->next)
3562       {
3563 	  if (cur_node->type == XML_ELEMENT_NODE)
3564 	    {
3565 		if (strcmp ((const char *) (cur_node->name), "Format") == 0)
3566 		  {
3567 		      xmlNodePtr child_node = cur_node->children;
3568 		      if (child_node != NULL)
3569 			{
3570 			    if (child_node->type == XML_TEXT_NODE)
3571 			      {
3572 				  if (cap->GmlMimeType == NULL)
3573 				    {
3574 					int ok = 0;
3575 					const char *format =
3576 					    (const char
3577 					     *) (child_node->content);
3578 					if (strcmp (format, "text/gml") == 0)
3579 					    ok = 1;
3580 					if (strcmp
3581 					    (format,
3582 					     "application/vnd.ogc.gml") == 0)
3583 					    ok = 1;
3584 					if (strcmp
3585 					    (format,
3586 					     "application/vnd.ogc.gml/3.1.1") ==
3587 					    0)
3588 					    ok = 1;
3589 					if (ok)
3590 					  {
3591 					      int len = strlen (format);
3592 					      cap->GmlMimeType =
3593 						  malloc (len + 1);
3594 					      strcpy (cap->GmlMimeType, format);
3595 					  }
3596 				    }
3597 				  if (cap->XmlMimeType == NULL)
3598 				    {
3599 					int ok = 0;
3600 					const char *format =
3601 					    (const char
3602 					     *) (child_node->content);
3603 					if (strcmp (format, "text/xml") == 0)
3604 					    ok = 1;
3605 					if (ok)
3606 					  {
3607 					      int len = strlen (format);
3608 					      cap->XmlMimeType =
3609 						  malloc (len + 1);
3610 					      strcpy (cap->XmlMimeType, format);
3611 					  }
3612 				    }
3613 			      }
3614 			}
3615 		  }
3616 		if (strcmp ((const char *) (cur_node->name), "DCPType") == 0)
3617 		    parse_wms_GetInfo_DCPType (cur_node->children, cap);
3618 	    }
3619       }
3620 }
3621 
3622 static void
parse_wms_getTileService(xmlNodePtr node,wmsCapabilitiesPtr cap)3623 parse_wms_getTileService (xmlNodePtr node, wmsCapabilitiesPtr cap)
3624 {
3625 /* recursively parsing the GetCapabilities/Capability/Request/GetTileService node */
3626     xmlNodePtr cur_node = NULL;
3627 
3628     for (cur_node = node; cur_node; cur_node = cur_node->next)
3629       {
3630 	  if (strcmp ((const char *) (cur_node->name), "DCPType") == 0)
3631 	      parse_wms_GetTileService_DCPType (cur_node->children, cap);
3632       }
3633 }
3634 
3635 static void
parse_wms_request(xmlNodePtr node,wmsCapabilitiesPtr cap)3636 parse_wms_request (xmlNodePtr node, wmsCapabilitiesPtr cap)
3637 {
3638 /* recursively parsing the GetCapabilities/Capability/Request node */
3639     xmlNodePtr cur_node = NULL;
3640 
3641     for (cur_node = node; cur_node; cur_node = cur_node->next)
3642       {
3643 	  if (cur_node->type == XML_ELEMENT_NODE)
3644 	    {
3645 		if (strcmp ((const char *) (cur_node->name), "GetMap") == 0)
3646 		    parse_wms_getMap (cur_node->children, cap);
3647 		if (strcmp ((const char *) (cur_node->name), "GetTileService")
3648 		    == 0)
3649 		    parse_wms_getTileService (cur_node->children, cap);
3650 		if (strcmp ((const char *) (cur_node->name), "GetFeatureInfo")
3651 		    == 0)
3652 		    parse_wms_getInfo (cur_node->children, cap);
3653 	    }
3654       }
3655 }
3656 
3657 static void
parse_wms_capability(xmlNodePtr node,wmsCapabilitiesPtr cap)3658 parse_wms_capability (xmlNodePtr node, wmsCapabilitiesPtr cap)
3659 {
3660 /* recursively parsing the GetCapabilities/Capability node */
3661     xmlNodePtr cur_node = NULL;
3662 
3663     for (cur_node = node; cur_node; cur_node = cur_node->next)
3664       {
3665 	  if (cur_node->type == XML_ELEMENT_NODE)
3666 	    {
3667 		if (strcmp ((const char *) (cur_node->name), "Request") == 0)
3668 		    parse_wms_request (cur_node->children, cap);
3669 		if (strcmp ((const char *) (cur_node->name), "Layer") == 0)
3670 		    parse_wms_layer (cur_node->children, cur_node->properties,
3671 				     cap);
3672 	    }
3673       }
3674 }
3675 
3676 static void
parse_capabilities(xmlNodePtr node,wmsCapabilitiesPtr cap)3677 parse_capabilities (xmlNodePtr node, wmsCapabilitiesPtr cap)
3678 {
3679 /* recursively parsing the GetCapabilities payload */
3680     xmlNodePtr cur_node = NULL;
3681 
3682     if (node)
3683 	cur_node = node->children;
3684     else
3685 	return;
3686 
3687     for (; cur_node; cur_node = cur_node->next)
3688       {
3689 	  if (cur_node->type == XML_ELEMENT_NODE)
3690 	    {
3691 		if (strcmp ((const char *) (cur_node->name), "Service") == 0)
3692 		    parse_wms_service (cur_node->children, cap);
3693 		if (strcmp ((const char *) (cur_node->name), "Capability") == 0)
3694 		    parse_wms_capability (cur_node->children, cap);
3695 	    }
3696       }
3697 }
3698 
3699 static void
parse_version(xmlNodePtr node,wmsCapabilitiesPtr cap)3700 parse_version (xmlNodePtr node, wmsCapabilitiesPtr cap)
3701 {
3702 /* attempting to extract the Version String */
3703     const char *version = NULL;
3704     struct _xmlAttr *attr = node->properties;
3705 
3706     while (attr != NULL)
3707       {
3708 	  if (attr->name != NULL)
3709 	    {
3710 		xmlNodePtr text;
3711 		if (strcmp ((const char *) (attr->name), "version") == 0)
3712 		  {
3713 		      text = attr->children;
3714 		      if (text->type == XML_TEXT_NODE)
3715 			  version = (const char *) (text->content);
3716 		  }
3717 	    }
3718 	  attr = attr->next;
3719       }
3720     if (version != NULL)
3721       {
3722 	  int len = strlen (version);
3723 	  if (cap->Version != NULL)
3724 	      free (cap->Version);
3725 	  cap->Version = malloc (len + 1);
3726 	  strcpy (cap->Version, version);
3727       }
3728 }
3729 
3730 static wmsCapabilitiesPtr
parse_wms_capabilities(const char * buf)3731 parse_wms_capabilities (const char *buf)
3732 {
3733 /* attempting to parse a WMS GetCapabilities answer */
3734     xmlDocPtr xml_doc;
3735     xmlNodePtr root;
3736     wmsMemBuffer xmlErr;
3737     wmsCapabilitiesPtr cap = NULL;
3738 
3739 /* testing if the XMLDocument is well-formed */
3740     wmsMemBufferInitialize (&xmlErr);
3741     xmlSetGenericErrorFunc (&xmlErr, wmsParsingError);
3742     xml_doc = xmlReadMemory (buf, strlen (buf), "GetCapabilities.xml", NULL, 0);
3743     if (xml_doc == NULL)
3744       {
3745 	  /* parsing error; not a well-formed XML */
3746 	  char *err = NULL;
3747 	  const char *p_err = "error unknown";
3748 	  if (xmlErr.Buffer != NULL)
3749 	    {
3750 		err = malloc (xmlErr.WriteOffset + 1);
3751 		memcpy (err, xmlErr.Buffer, xmlErr.WriteOffset);
3752 		*(err + xmlErr.WriteOffset) = '\0';
3753 		p_err = err;
3754 	    }
3755 	  fprintf (stderr, "XML parsing error: %s\n", p_err);
3756 	  if (err)
3757 	      free (err);
3758 	  wmsMemBufferReset (&xmlErr);
3759 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
3760 	  return NULL;
3761       }
3762     if (xmlErr.Buffer != NULL)
3763       {
3764 	  /* reporting some XML warning */
3765 	  char *err = malloc (xmlErr.WriteOffset + 1);
3766 	  memcpy (err, xmlErr.Buffer, xmlErr.WriteOffset);
3767 	  *(err + xmlErr.WriteOffset) = '\0';
3768 	  fprintf (stderr, "XML parsing warning: %s\n", err);
3769 	  free (err);
3770       }
3771     wmsMemBufferReset (&xmlErr);
3772 
3773 /* parsing XML nodes */
3774     cap = wmsAllocCapabilities ();
3775     root = xmlDocGetRootElement (xml_doc);
3776     parse_version (root, cap);
3777     parse_capabilities (root, cap);
3778     xmlFreeDoc (xml_doc);
3779 
3780     return cap;
3781 }
3782 
3783 static void
parse_wms_tiled_geoBBox(struct _xmlAttr * properties,wmsTiledLayerPtr lyr)3784 parse_wms_tiled_geoBBox (struct _xmlAttr *properties, wmsTiledLayerPtr lyr)
3785 {
3786 /* parsing a WMS TiledLayer/LatLonBoundingBox */
3787     struct _xmlAttr *attr = properties;
3788 
3789     while (attr != NULL)
3790       {
3791 	  if (attr->name != NULL)
3792 	    {
3793 		xmlNodePtr text;
3794 		if (strcmp ((const char *) (attr->name), "miny") == 0)
3795 		  {
3796 		      text = attr->children;
3797 		      if (text->type == XML_TEXT_NODE)
3798 			  lyr->MinLat = atof ((const char *) (text->content));
3799 		  }
3800 		if (strcmp ((const char *) (attr->name), "maxy") == 0)
3801 		  {
3802 		      text = attr->children;
3803 		      if (text->type == XML_TEXT_NODE)
3804 			  lyr->MaxLat = atof ((const char *) (text->content));
3805 		  }
3806 		if (strcmp ((const char *) (attr->name), "minx") == 0)
3807 		  {
3808 		      text = attr->children;
3809 		      if (text->type == XML_TEXT_NODE)
3810 			  lyr->MinLong = atof ((const char *) (text->content));
3811 		  }
3812 		if (strcmp ((const char *) (attr->name), "maxx") == 0)
3813 		  {
3814 		      text = attr->children;
3815 		      if (text->type == XML_TEXT_NODE)
3816 			  lyr->MaxLong = atof ((const char *) (text->content));
3817 		  }
3818 	    }
3819 	  attr = attr->next;
3820       }
3821 }
3822 
3823 static char *
normalize_pattern(const char * pattern)3824 normalize_pattern (const char *pattern)
3825 {
3826 /* normalizing a tile pattern */
3827     char *out;
3828     int len;
3829     const char *p_end = pattern;
3830     while (1)
3831       {
3832 	  if (*p_end == ' ' || *p_end == '\0' || *p_end == '\t'
3833 	      || *p_end == '\r' || *p_end == '\n')
3834 	      break;
3835 	  p_end++;
3836       }
3837     len = p_end - pattern;
3838     if (len <= 0)
3839 	return NULL;
3840     out = malloc (len + 1);
3841     memcpy (out, pattern, len);
3842     *(out + len) = '\0';
3843     return out;
3844 }
3845 
3846 static void
parse_wms_tiled_group_child(xmlNodePtr node,wmsTiledLayerPtr parent)3847 parse_wms_tiled_group_child (xmlNodePtr node, wmsTiledLayerPtr parent)
3848 {
3849 /* parsing a WMS Tiled Layer (child) definition */
3850     xmlNodePtr cur_node = NULL;
3851     xmlNodePtr child_node = NULL;
3852     const char *name = NULL;
3853     const char *title = NULL;
3854     const char *abstract = NULL;
3855     wmsTiledLayerPtr lyr;
3856 
3857     for (cur_node = node; cur_node; cur_node = cur_node->next)
3858       {
3859 	  if (cur_node->type == XML_ELEMENT_NODE)
3860 	    {
3861 		if (strcmp ((const char *) (cur_node->name), "Name") == 0)
3862 		  {
3863 		      child_node = cur_node->children;
3864 		      if (child_node != NULL)
3865 			{
3866 			    if (child_node->type == XML_TEXT_NODE)
3867 				name = (const char *) (child_node->content);
3868 			}
3869 		  }
3870 		if (strcmp ((const char *) (cur_node->name), "Title") == 0)
3871 		  {
3872 		      child_node = cur_node->children;
3873 		      if (child_node != NULL)
3874 			{
3875 			    if (child_node->type == XML_TEXT_NODE)
3876 				title = (const char *) (child_node->content);
3877 			}
3878 		  }
3879 		if (strcmp ((const char *) (cur_node->name), "Abstract") == 0)
3880 		  {
3881 		      child_node = cur_node->children;
3882 		      if (child_node != NULL)
3883 			{
3884 			    if (child_node->type == XML_TEXT_NODE)
3885 				abstract = (const char *) (child_node->content);
3886 			}
3887 		  }
3888 	    }
3889       }
3890     lyr = wmsAllocTiledLayer (name, title, abstract);
3891     if (parent->firstChild == NULL)
3892 	parent->firstChild = lyr;
3893     if (parent->lastChild != NULL)
3894 	parent->lastChild->next = lyr;
3895     parent->lastChild = lyr;
3896 
3897     for (cur_node = node; cur_node; cur_node = cur_node->next)
3898       {
3899 	  if (cur_node->type == XML_ELEMENT_NODE)
3900 	    {
3901 		int len;
3902 		if (strcmp
3903 		    ((const char *) (cur_node->name), "LatLonBoundingBox") == 0)
3904 		    parse_wms_tiled_geoBBox (cur_node->properties, lyr);
3905 		if (strcmp ((const char *) (cur_node->name), "Pad") == 0)
3906 		  {
3907 		      child_node = cur_node->children;
3908 		      if (child_node != NULL)
3909 			{
3910 			    if (child_node->type == XML_TEXT_NODE)
3911 			      {
3912 				  if (lyr->Pad != NULL)
3913 				      free (lyr->Pad);
3914 				  lyr->Pad = NULL;
3915 				  len =
3916 				      strlen ((const char
3917 					       *) (child_node->content));
3918 				  lyr->Pad = malloc (len + 1);
3919 				  strcpy (lyr->Pad,
3920 					  (const char *) (child_node->content));
3921 			      }
3922 			}
3923 		  }
3924 		if (strcmp ((const char *) (cur_node->name), "Bands") == 0)
3925 		  {
3926 		      child_node = cur_node->children;
3927 		      if (child_node != NULL)
3928 			{
3929 			    if (child_node->type == XML_TEXT_NODE)
3930 			      {
3931 				  if (lyr->Bands != NULL)
3932 				      free (lyr->Bands);
3933 				  lyr->Bands = NULL;
3934 				  len =
3935 				      strlen ((const char
3936 					       *) (child_node->content));
3937 				  lyr->Bands = malloc (len + 1);
3938 				  strcpy (lyr->Bands,
3939 					  (const char *) (child_node->content));
3940 			      }
3941 			}
3942 		  }
3943 		if (strcmp ((const char *) (cur_node->name), "DataType") == 0)
3944 		  {
3945 		      child_node = cur_node->children;
3946 		      if (child_node != NULL)
3947 			{
3948 			    if (child_node->type == XML_TEXT_NODE)
3949 			      {
3950 				  if (lyr->DataType != NULL)
3951 				      free (lyr->DataType);
3952 				  lyr->DataType = NULL;
3953 				  len =
3954 				      strlen ((const char
3955 					       *) (child_node->content));
3956 				  lyr->DataType = malloc (len + 1);
3957 				  strcpy (lyr->DataType,
3958 					  (const char *) (child_node->content));
3959 			      }
3960 			}
3961 		  }
3962 		if (strcmp ((const char *) (cur_node->name), "TilePattern") ==
3963 		    0)
3964 		  {
3965 		      child_node = cur_node->children;
3966 		      if (child_node != NULL)
3967 			{
3968 			    if (child_node->type == XML_TEXT_NODE)
3969 			      {
3970 				  const char *pattern =
3971 				      (const char *) (child_node->content);
3972 				  char *norm_pattern =
3973 				      normalize_pattern (pattern);
3974 				  if (norm_pattern != NULL)
3975 				    {
3976 					wmsTilePatternPtr pattern =
3977 					    wmsAllocTilePattern (norm_pattern);
3978 					if (lyr->firstPattern == NULL)
3979 					    lyr->firstPattern = pattern;
3980 					if (lyr->lastPattern != NULL)
3981 					    lyr->lastPattern->next = pattern;
3982 					lyr->lastPattern = pattern;
3983 				    }
3984 			      }
3985 			}
3986 		  }
3987 	    }
3988       }
3989 }
3990 
3991 static void
parse_wms_tiled_groups_child(xmlNodePtr node,wmsTiledLayerPtr parent)3992 parse_wms_tiled_groups_child (xmlNodePtr node, wmsTiledLayerPtr parent)
3993 {
3994 /* parsing a WMS Tiled (Group) Layer definition */
3995     xmlNodePtr cur_node = NULL;
3996     xmlNodePtr child_node = NULL;
3997     const char *name = NULL;
3998     const char *title = NULL;
3999     const char *abstract = NULL;
4000     wmsTiledLayerPtr lyr;
4001 
4002     for (cur_node = node; cur_node; cur_node = cur_node->next)
4003       {
4004 	  if (cur_node->type == XML_ELEMENT_NODE)
4005 	    {
4006 		if (strcmp ((const char *) (cur_node->name), "Name") == 0)
4007 		  {
4008 		      child_node = cur_node->children;
4009 		      if (child_node != NULL)
4010 			{
4011 			    if (child_node->type == XML_TEXT_NODE)
4012 				name = (const char *) (child_node->content);
4013 			}
4014 		  }
4015 		if (strcmp ((const char *) (cur_node->name), "Title") == 0)
4016 		  {
4017 		      child_node = cur_node->children;
4018 		      if (child_node != NULL)
4019 			{
4020 			    if (child_node->type == XML_TEXT_NODE)
4021 				title = (const char *) (child_node->content);
4022 			}
4023 		  }
4024 		if (strcmp ((const char *) (cur_node->name), "Abstract") == 0)
4025 		  {
4026 		      child_node = cur_node->children;
4027 		      if (child_node != NULL)
4028 			{
4029 			    if (child_node->type == XML_TEXT_NODE)
4030 				abstract = (const char *) (child_node->content);
4031 			}
4032 		  }
4033 	    }
4034       }
4035     lyr = wmsAllocTiledLayer (name, title, abstract);
4036     if (parent->firstChild == NULL)
4037 	parent->firstChild = lyr;
4038     if (parent->lastChild != NULL)
4039 	parent->lastChild->next = lyr;
4040     parent->lastChild = lyr;
4041 
4042     for (cur_node = node; cur_node; cur_node = cur_node->next)
4043       {
4044 	  if (cur_node->type == XML_ELEMENT_NODE)
4045 	    {
4046 		if (strcmp ((const char *) (cur_node->name), "TiledGroup") == 0)
4047 		    parse_wms_tiled_group_child (cur_node->children, lyr);
4048 		if (strcmp ((const char *) (cur_node->name), "TiledGroups") ==
4049 		    0)
4050 		    parse_wms_tiled_groups_child (cur_node->children, lyr);
4051 	    }
4052       }
4053 }
4054 
4055 static void
parse_wms_tiled_group(xmlNodePtr node,wmsCapabilitiesPtr cap)4056 parse_wms_tiled_group (xmlNodePtr node, wmsCapabilitiesPtr cap)
4057 {
4058 /* parsing a WMS Tiled Layer definition */
4059     xmlNodePtr cur_node = NULL;
4060     xmlNodePtr child_node = NULL;
4061     const char *name = NULL;
4062     const char *title = NULL;
4063     const char *abstract = NULL;
4064     wmsTiledLayerPtr lyr;
4065 
4066     for (cur_node = node; cur_node; cur_node = cur_node->next)
4067       {
4068 	  if (cur_node->type == XML_ELEMENT_NODE)
4069 	    {
4070 		if (strcmp ((const char *) (cur_node->name), "Name") == 0)
4071 		  {
4072 		      child_node = cur_node->children;
4073 		      if (child_node != NULL)
4074 			{
4075 			    if (child_node->type == XML_TEXT_NODE)
4076 				name = (const char *) (child_node->content);
4077 			}
4078 		  }
4079 		if (strcmp ((const char *) (cur_node->name), "Title") == 0)
4080 		  {
4081 		      child_node = cur_node->children;
4082 		      if (child_node != NULL)
4083 			{
4084 			    if (child_node->type == XML_TEXT_NODE)
4085 				title = (const char *) (child_node->content);
4086 			}
4087 		  }
4088 		if (strcmp ((const char *) (cur_node->name), "Abstract") == 0)
4089 		  {
4090 		      child_node = cur_node->children;
4091 		      if (child_node != NULL)
4092 			{
4093 			    if (child_node->type == XML_TEXT_NODE)
4094 				abstract = (const char *) (child_node->content);
4095 			}
4096 		  }
4097 	    }
4098       }
4099     lyr = wmsAllocTiledLayer (name, title, abstract);
4100     if (cap->firstTiled == NULL)
4101 	cap->firstTiled = lyr;
4102     if (cap->lastTiled != NULL)
4103 	cap->lastTiled->next = lyr;
4104     cap->lastTiled = lyr;
4105 
4106     for (cur_node = node; cur_node; cur_node = cur_node->next)
4107       {
4108 	  if (cur_node->type == XML_ELEMENT_NODE)
4109 	    {
4110 		int len;
4111 		if (strcmp
4112 		    ((const char *) (cur_node->name), "LatLonBoundingBox") == 0)
4113 		    parse_wms_tiled_geoBBox (cur_node->properties, lyr);
4114 		if (strcmp ((const char *) (cur_node->name), "Pad") == 0)
4115 		  {
4116 		      child_node = cur_node->children;
4117 		      if (child_node != NULL)
4118 			{
4119 			    if (child_node->type == XML_TEXT_NODE)
4120 			      {
4121 				  if (lyr->Pad != NULL)
4122 				      free (lyr->Pad);
4123 				  lyr->Pad = NULL;
4124 				  len =
4125 				      strlen ((const char
4126 					       *) (child_node->content));
4127 				  lyr->Pad = malloc (len + 1);
4128 				  strcpy (lyr->Pad,
4129 					  (const char *) (child_node->content));
4130 			      }
4131 			}
4132 		  }
4133 		if (strcmp ((const char *) (cur_node->name), "Bands") == 0)
4134 		  {
4135 		      child_node = cur_node->children;
4136 		      if (child_node != NULL)
4137 			{
4138 			    if (child_node->type == XML_TEXT_NODE)
4139 			      {
4140 				  if (lyr->Bands != NULL)
4141 				      free (lyr->Bands);
4142 				  lyr->Bands = NULL;
4143 				  len =
4144 				      strlen ((const char
4145 					       *) (child_node->content));
4146 				  lyr->Bands = malloc (len + 1);
4147 				  strcpy (lyr->Bands,
4148 					  (const char *) (child_node->content));
4149 			      }
4150 			}
4151 		  }
4152 		if (strcmp ((const char *) (cur_node->name), "DataType") == 0)
4153 		  {
4154 		      child_node = cur_node->children;
4155 		      if (child_node != NULL)
4156 			{
4157 			    if (child_node->type == XML_TEXT_NODE)
4158 			      {
4159 				  if (lyr->DataType != NULL)
4160 				      free (lyr->DataType);
4161 				  lyr->DataType = NULL;
4162 				  len =
4163 				      strlen ((const char
4164 					       *) (child_node->content));
4165 				  lyr->DataType = malloc (len + 1);
4166 				  strcpy (lyr->DataType,
4167 					  (const char *) (child_node->content));
4168 			      }
4169 			}
4170 		  }
4171 		if (strcmp ((const char *) (cur_node->name), "TilePattern") ==
4172 		    0)
4173 		  {
4174 		      child_node = cur_node->children;
4175 		      if (child_node != NULL)
4176 			{
4177 			    if (child_node->type == XML_TEXT_NODE)
4178 			      {
4179 				  const char *pattern =
4180 				      (const char *) (child_node->content);
4181 				  char *norm_pattern =
4182 				      normalize_pattern (pattern);
4183 				  if (norm_pattern != NULL)
4184 				    {
4185 					wmsTilePatternPtr pattern =
4186 					    wmsAllocTilePattern (norm_pattern);
4187 					if (lyr->firstPattern == NULL)
4188 					    lyr->firstPattern = pattern;
4189 					if (lyr->lastPattern != NULL)
4190 					    lyr->lastPattern->next = pattern;
4191 					lyr->lastPattern = pattern;
4192 				    }
4193 			      }
4194 			}
4195 		  }
4196 	    }
4197       }
4198 }
4199 
4200 static void
parse_wms_tiled_groups(xmlNodePtr node,wmsCapabilitiesPtr cap)4201 parse_wms_tiled_groups (xmlNodePtr node, wmsCapabilitiesPtr cap)
4202 {
4203 /* parsing a WMS Tiled (Group) Layer definition */
4204     xmlNodePtr cur_node = NULL;
4205     xmlNodePtr child_node = NULL;
4206     const char *name = NULL;
4207     const char *title = NULL;
4208     const char *abstract = NULL;
4209     wmsTiledLayerPtr lyr;
4210 
4211     for (cur_node = node; cur_node; cur_node = cur_node->next)
4212       {
4213 	  if (cur_node->type == XML_ELEMENT_NODE)
4214 	    {
4215 		if (strcmp ((const char *) (cur_node->name), "Name") == 0)
4216 		  {
4217 		      child_node = cur_node->children;
4218 		      if (child_node != NULL)
4219 			{
4220 			    if (child_node->type == XML_TEXT_NODE)
4221 				name = (const char *) (child_node->content);
4222 			}
4223 		  }
4224 		if (strcmp ((const char *) (cur_node->name), "Title") == 0)
4225 		  {
4226 		      child_node = cur_node->children;
4227 		      if (child_node != NULL)
4228 			{
4229 			    if (child_node->type == XML_TEXT_NODE)
4230 				title = (const char *) (child_node->content);
4231 			}
4232 		  }
4233 		if (strcmp ((const char *) (cur_node->name), "Abstract") == 0)
4234 		  {
4235 		      child_node = cur_node->children;
4236 		      if (child_node != NULL)
4237 			{
4238 			    if (child_node->type == XML_TEXT_NODE)
4239 				abstract = (const char *) (child_node->content);
4240 			}
4241 		  }
4242 	    }
4243       }
4244     lyr = wmsAllocTiledLayer (name, title, abstract);
4245     if (cap->firstTiled == NULL)
4246 	cap->firstTiled = lyr;
4247     if (cap->lastTiled != NULL)
4248 	cap->lastTiled->next = lyr;
4249     cap->lastTiled = lyr;
4250 
4251     for (cur_node = node; cur_node; cur_node = cur_node->next)
4252       {
4253 	  if (cur_node->type == XML_ELEMENT_NODE)
4254 	    {
4255 		if (strcmp ((const char *) (cur_node->name), "TiledGroup") == 0)
4256 		    parse_wms_tiled_group_child (cur_node->children, lyr);
4257 		if (strcmp ((const char *) (cur_node->name), "TiledGroups") ==
4258 		    0)
4259 		    parse_wms_tiled_groups_child (cur_node->children, lyr);
4260 	    }
4261       }
4262 }
4263 
4264 static void
parse_tile_service_info(xmlNodePtr node,wmsCapabilitiesPtr cap)4265 parse_tile_service_info (xmlNodePtr node, wmsCapabilitiesPtr cap)
4266 {
4267 /* recursively parsing the GetTileService/Service payload */
4268     xmlNodePtr cur_node = NULL;
4269 
4270     if (node)
4271 	cur_node = node->children;
4272     else
4273 	return;
4274 
4275     for (; cur_node; cur_node = cur_node->next)
4276       {
4277 	  if (cur_node->type == XML_ELEMENT_NODE)
4278 	    {
4279 		int len;
4280 		xmlNodePtr child_node;
4281 		const char *value;
4282 		if (strcmp ((const char *) (cur_node->name), "Name") == 0)
4283 		  {
4284 		      if (cap->TileServiceName != NULL)
4285 			  free (cap->TileServiceName);
4286 		      cap->TileServiceName = NULL;
4287 		      child_node = cur_node->children;
4288 		      if (child_node != NULL)
4289 			{
4290 			    if (child_node->type == XML_TEXT_NODE)
4291 				value = (const char *) (child_node->content);
4292 			    if (value != NULL)
4293 			      {
4294 				  len = strlen (value);
4295 				  cap->TileServiceName = malloc (len + 1);
4296 				  strcpy (cap->TileServiceName, value);
4297 			      }
4298 			}
4299 		  }
4300 		if (strcmp ((const char *) (cur_node->name), "Title") == 0)
4301 		  {
4302 		      if (cap->TileServiceTitle != NULL)
4303 			  free (cap->TileServiceTitle);
4304 		      cap->TileServiceTitle = NULL;
4305 		      child_node = cur_node->children;
4306 		      if (child_node != NULL)
4307 			{
4308 			    if (child_node->type == XML_TEXT_NODE)
4309 				value = (const char *) (child_node->content);
4310 			    if (value != NULL)
4311 			      {
4312 				  len = strlen (value);
4313 				  cap->TileServiceTitle = malloc (len + 1);
4314 				  strcpy (cap->TileServiceTitle, value);
4315 			      }
4316 			}
4317 		  }
4318 		if (strcmp ((const char *) (cur_node->name), "Abstract") == 0)
4319 		  {
4320 		      if (cap->TileServiceAbstract != NULL)
4321 			  free (cap->TileServiceAbstract);
4322 		      cap->TileServiceAbstract = NULL;
4323 		      child_node = cur_node->children;
4324 		      if (child_node != NULL)
4325 			{
4326 			    if (child_node->type == XML_TEXT_NODE)
4327 				value = (const char *) (child_node->content);
4328 			    if (value != NULL)
4329 			      {
4330 				  len = strlen (value);
4331 				  cap->TileServiceAbstract = malloc (len + 1);
4332 				  strcpy (cap->TileServiceAbstract, value);
4333 			      }
4334 			}
4335 		  }
4336 	    }
4337       }
4338 }
4339 
4340 static void
parse_tiled_patterns(xmlNodePtr node,wmsCapabilitiesPtr cap)4341 parse_tiled_patterns (xmlNodePtr node, wmsCapabilitiesPtr cap)
4342 {
4343 /* recursively parsing the GetTileService/TiledPatterns payload */
4344     xmlNodePtr cur_node = NULL;
4345 
4346     if (node)
4347 	cur_node = node->children;
4348     else
4349 	return;
4350 
4351     for (; cur_node; cur_node = cur_node->next)
4352       {
4353 	  if (cur_node->type == XML_ELEMENT_NODE)
4354 	    {
4355 		if (strcmp ((const char *) (cur_node->name), "TiledGroup") == 0)
4356 		    parse_wms_tiled_group (cur_node->children, cap);
4357 		if (strcmp ((const char *) (cur_node->name), "TiledGroups") ==
4358 		    0)
4359 		    parse_wms_tiled_groups (cur_node->children, cap);
4360 	    }
4361       }
4362 }
4363 
4364 static void
parse_tile_service(xmlNodePtr node,wmsCapabilitiesPtr cap)4365 parse_tile_service (xmlNodePtr node, wmsCapabilitiesPtr cap)
4366 {
4367 /* recursively parsing the GetTileService payload */
4368     xmlNodePtr cur_node = NULL;
4369 
4370     if (node)
4371 	cur_node = node->children;
4372     else
4373 	return;
4374 
4375     for (; cur_node; cur_node = cur_node->next)
4376       {
4377 	  if (cur_node->type == XML_ELEMENT_NODE)
4378 	    {
4379 		if (strcmp ((const char *) (cur_node->name), "Service") == 0)
4380 		    parse_tile_service_info (cur_node, cap);
4381 		if (strcmp ((const char *) (cur_node->name), "TiledPatterns") ==
4382 		    0)
4383 		    parse_tiled_patterns (cur_node, cap);
4384 	    }
4385       }
4386 }
4387 
4388 static void
parse_wms_get_tile_service(wmsCapabilitiesPtr capabilities,const char * buf)4389 parse_wms_get_tile_service (wmsCapabilitiesPtr capabilities, const char *buf)
4390 {
4391 /* attempting to parse a WMS GetTileService answer */
4392     xmlDocPtr xml_doc;
4393     xmlNodePtr root;
4394     wmsMemBuffer xmlErr;
4395 
4396 /* testing if the XMLDocument is well-formed */
4397     wmsMemBufferInitialize (&xmlErr);
4398     xmlSetGenericErrorFunc (&xmlErr, wmsParsingError);
4399     xml_doc = xmlReadMemory (buf, strlen (buf), "GetTileService.xml", NULL, 0);
4400     if (xml_doc == NULL)
4401       {
4402 	  /* parsing error; not a well-formed XML */
4403 	  char *err = NULL;
4404 	  const char *p_err = "error unknown";
4405 	  if (xmlErr.Buffer != NULL)
4406 	    {
4407 		err = malloc (xmlErr.WriteOffset + 1);
4408 		memcpy (err, xmlErr.Buffer, xmlErr.WriteOffset);
4409 		*(err + xmlErr.WriteOffset) = '\0';
4410 		p_err = err;
4411 	    }
4412 	  fprintf (stderr, "XML parsing error: %s\n", p_err);
4413 	  if (err)
4414 	      free (err);
4415 	  wmsMemBufferReset (&xmlErr);
4416 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
4417 	  return;
4418       }
4419     if (xmlErr.Buffer != NULL)
4420       {
4421 	  /* reporting some XML warning */
4422 	  char *err = malloc (xmlErr.WriteOffset + 1);
4423 	  memcpy (err, xmlErr.Buffer, xmlErr.WriteOffset);
4424 	  *(err + xmlErr.WriteOffset) = '\0';
4425 	  fprintf (stderr, "XML parsing warning: %s\n", err);
4426 	  free (err);
4427       }
4428     wmsMemBufferReset (&xmlErr);
4429 
4430 /* parsing XML nodes */
4431     root = xmlDocGetRootElement (xml_doc);
4432     parse_tile_service (root, capabilities);
4433     xmlFreeDoc (xml_doc);
4434 }
4435 
4436 static void
parse_wms_gml_geom(wmsMemBufferPtr gmlBuf,xmlNodePtr node)4437 parse_wms_gml_geom (wmsMemBufferPtr gmlBuf, xmlNodePtr node)
4438 {
4439 /* recursively reassembling the GML Geometry */
4440     xmlNodePtr cur_node = NULL;
4441 
4442     for (cur_node = node; cur_node; cur_node = cur_node->next)
4443       {
4444 	  if (cur_node->type == XML_ELEMENT_NODE)
4445 	    {
4446 		/* found some internal GML Geometry Tag */
4447 		struct _xmlAttr *attr;
4448 		char *tag_name;
4449 		if (cur_node->ns == NULL)
4450 		    tag_name = sqlite3_mprintf ("<%s", cur_node->name);
4451 		else
4452 		    tag_name =
4453 			sqlite3_mprintf ("<%s:%s", cur_node->ns->prefix,
4454 					 cur_node->name);
4455 		wmsMemBufferAppend (gmlBuf, (unsigned char *) tag_name,
4456 				    strlen (tag_name));
4457 		sqlite3_free (tag_name);
4458 		attr = cur_node->properties;
4459 		while (attr != NULL)
4460 		  {
4461 		      /* eventual node attributes */
4462 		      if (attr->type == XML_ATTRIBUTE_NODE)
4463 			{
4464 			    const char *value = "";
4465 			    xmlNodePtr text = attr->children;
4466 			    if (text != NULL)
4467 			      {
4468 				  if (text->type == XML_TEXT_NODE)
4469 				      value = (const char *) (text->content);
4470 			      }
4471 			    if (attr->ns == NULL)
4472 				tag_name =
4473 				    sqlite3_mprintf (" %s=\"%s\"", attr->name,
4474 						     value);
4475 			    else
4476 				tag_name =
4477 				    sqlite3_mprintf (" %s:%s=\"%s\"",
4478 						     attr->ns->prefix,
4479 						     attr->name, value);
4480 			    wmsMemBufferAppend (gmlBuf,
4481 						(unsigned char *) tag_name,
4482 						strlen (tag_name));
4483 			    sqlite3_free (tag_name);
4484 			}
4485 		      attr = attr->next;
4486 		  }
4487 		wmsMemBufferAppend (gmlBuf, (unsigned char *) ">", 1);
4488 		parse_wms_gml_geom (gmlBuf, cur_node->children);
4489 		if (cur_node->ns == NULL)
4490 		    tag_name = sqlite3_mprintf ("</%s>", cur_node->name);
4491 		else
4492 		    tag_name =
4493 			sqlite3_mprintf ("</%s:%s>", cur_node->ns->prefix,
4494 					 cur_node->name);
4495 		wmsMemBufferAppend (gmlBuf, (unsigned char *) tag_name,
4496 				    strlen (tag_name));
4497 		sqlite3_free (tag_name);
4498 	    }
4499 	  if (cur_node->type == XML_TEXT_NODE)
4500 	    {
4501 		/* found a Text item */
4502 		wmsMemBufferAppend (gmlBuf,
4503 				    (unsigned char *) (cur_node->content),
4504 				    strlen ((const char
4505 					     *) (cur_node->content)));
4506 	    }
4507       }
4508 }
4509 
4510 static void
parse_wms_feature_attribute(xmlNodePtr node,wmsFeatureMemberPtr member)4511 parse_wms_feature_attribute (xmlNodePtr node, wmsFeatureMemberPtr member)
4512 {
4513 /* parsing the GetFeatureInfo/featureAttribute node */
4514     xmlNodePtr cur_node = NULL;
4515 
4516     for (cur_node = node; cur_node; cur_node = cur_node->next)
4517       {
4518 	  if (cur_node->type == XML_ELEMENT_NODE)
4519 	    {
4520 		xmlNodePtr text = cur_node->children;
4521 		if (text == NULL)
4522 		    continue;
4523 		if (text->type == XML_TEXT_NODE)
4524 		  {
4525 		      /* found an attribute */
4526 		      {
4527 			  char *value = NULL;
4528 			  if (text->content != NULL)
4529 			    {
4530 				int len =
4531 				    strlen ((const char *) (text->content));
4532 				value = malloc (len + 1);
4533 				strcpy (value, (const char *) (text->content));
4534 			    }
4535 			  wmsAddFeatureMemberAttribute (member,
4536 							(const char
4537 							 *) (cur_node->name),
4538 							value);
4539 		      }
4540 		  }
4541 		if (text->type == XML_ELEMENT_NODE)
4542 		  {
4543 		      /* probably found the GML Geometry - attempting to reassemble */
4544 		      char *gml = NULL;
4545 		      wmsMemBuffer gmlBuf;
4546 		      wmsMemBufferInitialize (&gmlBuf);
4547 		      parse_wms_gml_geom (&gmlBuf, text);
4548 		      if (gmlBuf.WriteOffset > 0)
4549 			{
4550 			    gml = malloc (gmlBuf.WriteOffset + 1);
4551 			    memcpy (gml, gmlBuf.Buffer, gmlBuf.WriteOffset);
4552 			    *(gml + gmlBuf.WriteOffset) = '\0';
4553 			}
4554 		      wmsMemBufferReset (&gmlBuf);
4555 		      wmsAddFeatureMemberAttribute (member,
4556 						    (const char
4557 						     *) (cur_node->name), gml);
4558 		  }
4559 	    }
4560       }
4561 }
4562 
4563 
4564 static void
parse_wms_feature_member(xmlNodePtr node,wmsFeatureCollectionPtr coll)4565 parse_wms_feature_member (xmlNodePtr node, wmsFeatureCollectionPtr coll)
4566 {
4567 /* parsing the GetFeatureInfo/featureMember node */
4568     xmlNodePtr cur_node = NULL;
4569 
4570     for (cur_node = node; cur_node; cur_node = cur_node->next)
4571       {
4572 	  if (cur_node->type == XML_ELEMENT_NODE)
4573 	    {
4574 
4575 		wmsFeatureMemberPtr member =
4576 		    wmsAllocFeatureMember ((const char *) (cur_node->name));
4577 		parse_wms_feature_attribute (cur_node->children, member);
4578 		if (member->first == NULL)
4579 		  {
4580 		      /* empty feature */
4581 		      wmsFreeFeatureMember (member);
4582 		  }
4583 		/* appending the feature to the collection */
4584 		if (coll->first == NULL)
4585 		    coll->first = member;
4586 		if (coll->last != NULL)
4587 		    coll->last->next = member;
4588 		coll->last = member;
4589 	    }
4590       }
4591 }
4592 
4593 static void
parse_ms_layer(xmlNodePtr node,wmsFeatureCollectionPtr coll,const char * feature_name)4594 parse_ms_layer (xmlNodePtr node, wmsFeatureCollectionPtr coll,
4595 		const char *feature_name)
4596 {
4597 /* recursively parsing msGMLOutput features from a layer */
4598     xmlNodePtr cur_node = NULL;
4599 
4600     for (cur_node = node; cur_node; cur_node = cur_node->next)
4601       {
4602 	  if (cur_node->type == XML_ELEMENT_NODE)
4603 	    {
4604 		if (strcmp ((const char *) (cur_node->name), feature_name) == 0)
4605 		    parse_wms_feature_member (cur_node, coll);
4606 		else
4607 		    parse_ms_layer (cur_node->children, coll, feature_name);
4608 	    }
4609       }
4610 }
4611 
4612 static char *
make_feature_name(const char * layer_name)4613 make_feature_name (const char *layer_name)
4614 {
4615 /* building the expected feature name */
4616     char *name;
4617     int len = strlen (layer_name);
4618     if (len <= 6)
4619 	return NULL;
4620     if (strcmp (layer_name + len - 6, "_layer") != 0)
4621 	return NULL;
4622     name = malloc (len - 6 + 9);
4623     strncpy (name, layer_name, len - 6);
4624     name[len - 6] = '\0';
4625     strcat (name, "_feature");
4626     return name;
4627 }
4628 
4629 static void
parse_ms_gml_output(xmlNodePtr node,wmsFeatureCollectionPtr coll)4630 parse_ms_gml_output (xmlNodePtr node, wmsFeatureCollectionPtr coll)
4631 {
4632 /* parsing the msGMLOutput payload */
4633     xmlNodePtr cur_node = NULL;
4634     char *feature_name = NULL;
4635     if (strcmp ((const char *) (node->name), "msGMLOutput") != 0)
4636 	return;
4637 
4638     if (node)
4639 	cur_node = node->children;
4640     else
4641 	return;
4642 
4643     for (; cur_node; cur_node = cur_node->next)
4644       {
4645 	  if (cur_node->type == XML_ELEMENT_NODE)
4646 	    {
4647 		if (feature_name == NULL)
4648 		    feature_name =
4649 			make_feature_name ((const char *) (cur_node->name));
4650 		if (feature_name == NULL)
4651 		    continue;
4652 		parse_ms_layer (cur_node->children, coll, feature_name);
4653 	    }
4654       }
4655     if (feature_name != NULL)
4656 	free (feature_name);
4657 }
4658 
4659 static void
parse_esri_xml_field(struct _xmlAttr * properties,wmsFeatureMemberPtr member)4660 parse_esri_xml_field (struct _xmlAttr *properties, wmsFeatureMemberPtr member)
4661 {
4662 /* parsing an ESRI <Fields> based on XML attributes */
4663     struct _xmlAttr *attr = properties;
4664 
4665     while (attr != NULL)
4666       {
4667 	  if (attr->name != NULL)
4668 	    {
4669 		char *value = NULL;
4670 		xmlNodePtr text = attr->children;
4671 		if (text != NULL)
4672 		  {
4673 		      if (text->type == XML_TEXT_NODE)
4674 			{
4675 			    if (text->content != NULL)
4676 			      {
4677 				  int len =
4678 				      strlen ((const char *) (text->content));
4679 				  value = malloc (len + 1);
4680 				  strcpy (value,
4681 					  (const char *) (text->content));
4682 			      }
4683 			}
4684 		  }
4685 		else
4686 		  {
4687 		      value = malloc (1);
4688 		      *value = '\0';
4689 		  }
4690 		wmsAddFeatureMemberAttribute (member,
4691 					      (const char *) (attr->name),
4692 					      value);
4693 	    }
4694 	  attr = attr->next;
4695       }
4696 }
4697 
4698 static void
parse_esri_xml_output(xmlNodePtr node,wmsFeatureCollectionPtr coll)4699 parse_esri_xml_output (xmlNodePtr node, wmsFeatureCollectionPtr coll)
4700 {
4701 /* parsing the ESRI-like XML payload */
4702     xmlNodePtr cur_node = NULL;
4703     if (strcmp ((const char *) (node->name), "FeatureInfoResponse") != 0)
4704 	return;
4705 
4706     if (node)
4707 	cur_node = node->children;
4708     else
4709 	return;
4710 
4711     for (; cur_node; cur_node = cur_node->next)
4712       {
4713 	  if (cur_node->type == XML_ELEMENT_NODE)
4714 	    {
4715 		if (strcmp ((const char *) (cur_node->name), "Fields") != 0)
4716 		  {
4717 		      struct _xmlAttr *attr = cur_node->properties;
4718 		      if (attr != NULL)
4719 			{
4720 			    wmsFeatureMemberPtr member =
4721 				wmsAllocFeatureMember ((const char
4722 							*) (cur_node->name));
4723 			    parse_esri_xml_field (attr, member);
4724 			    /* appending the feature to the collection */
4725 			    if (coll->first == NULL)
4726 				coll->first = member;
4727 			    if (coll->last != NULL)
4728 				coll->last->next = member;
4729 			    coll->last = member;
4730 			}
4731 		  }
4732 	    }
4733       }
4734 }
4735 
4736 static void
parse_feature_collection(xmlNodePtr node,wmsFeatureCollectionPtr coll)4737 parse_feature_collection (xmlNodePtr node, wmsFeatureCollectionPtr coll)
4738 {
4739 /* parsing the GetFeatureInfo payload */
4740     xmlNodePtr cur_node = NULL;
4741     if (strcmp ((const char *) (node->name), "FeatureInfoResponse") == 0)
4742       {
4743 	  parse_esri_xml_output (node, coll);
4744 	  return;
4745       }
4746     if (strcmp ((const char *) (node->name), "msGMLOutput") == 0)
4747       {
4748 	  parse_ms_gml_output (node, coll);
4749 	  return;
4750       }
4751     if (strcmp ((const char *) (node->name), "FeatureCollection") != 0)
4752 	return;
4753 
4754     if (node)
4755 	cur_node = node->children;
4756     else
4757 	return;
4758 
4759     for (; cur_node; cur_node = cur_node->next)
4760       {
4761 	  if (cur_node->type == XML_ELEMENT_NODE)
4762 	    {
4763 		if (strcmp ((const char *) (cur_node->name), "featureMember") ==
4764 		    0)
4765 		    parse_wms_feature_member (cur_node->children, coll);
4766 	    }
4767       }
4768 }
4769 
4770 static wmsFeatureCollectionPtr
parse_wms_feature_collection(const char * buf)4771 parse_wms_feature_collection (const char *buf)
4772 {
4773 /* attempting to parse a WMS GetFeatureInfo answer */
4774     xmlDocPtr xml_doc;
4775     xmlNodePtr root;
4776     wmsMemBuffer xmlErr;
4777     wmsFeatureCollectionPtr coll = NULL;
4778 
4779 /* testing if the XMLDocument is well-formed */
4780     wmsMemBufferInitialize (&xmlErr);
4781     xmlSetGenericErrorFunc (&xmlErr, wmsParsingError);
4782     xml_doc = xmlReadMemory (buf, strlen (buf), "GetFeatureInfo.xml", NULL, 0);
4783     if (xml_doc == NULL)
4784       {
4785 	  /* parsing error; not a well-formed XML */
4786 	  char *err = NULL;
4787 	  const char *p_err = "error unknown";
4788 	  if (xmlErr.Buffer != NULL)
4789 	    {
4790 		err = malloc (xmlErr.WriteOffset + 1);
4791 		memcpy (err, xmlErr.Buffer, xmlErr.WriteOffset);
4792 		*(err + xmlErr.WriteOffset) = '\0';
4793 		p_err = err;
4794 	    }
4795 	  fprintf (stderr, "XML parsing error: %s\n", p_err);
4796 	  if (err)
4797 	      free (err);
4798 	  wmsMemBufferReset (&xmlErr);
4799 	  xmlSetGenericErrorFunc ((void *) stderr, NULL);
4800 	  return NULL;
4801       }
4802     if (xmlErr.Buffer != NULL)
4803       {
4804 	  /* reporting some XML warning */
4805 	  char *err = malloc (xmlErr.WriteOffset + 1);
4806 	  memcpy (err, xmlErr.Buffer, xmlErr.WriteOffset);
4807 	  *(err + xmlErr.WriteOffset) = '\0';
4808 	  fprintf (stderr, "XML parsing warning: %s\n", err);
4809 	  free (err);
4810       }
4811     wmsMemBufferReset (&xmlErr);
4812 
4813 /* parsing XML nodes */
4814     coll = wmsAllocFeatureCollection ();
4815     root = xmlDocGetRootElement (xml_doc);
4816     parse_feature_collection (root, coll);
4817     xmlFreeDoc (xml_doc);
4818 
4819     if (coll != NULL)
4820       {
4821 	  if (coll->first == NULL)
4822 	    {
4823 		/* empty collection */
4824 		wmsFreeFeatureCollection (coll);
4825 		coll = NULL;
4826 	    }
4827       }
4828 
4829     return coll;
4830 }
4831 
4832 static int
query_TileService(rl2WmsCachePtr cache_handle,wmsCapabilitiesPtr capabilities,const char * proxy)4833 query_TileService (rl2WmsCachePtr cache_handle, wmsCapabilitiesPtr capabilities,
4834 		   const char *proxy)
4835 {
4836 /* attempting to get and parse a WMS GetTileService request */
4837     CURL *curl = NULL;
4838     CURLcode res;
4839     wmsMemBuffer headerBuf;
4840     wmsMemBuffer bodyBuf;
4841     int http_status;
4842     char *http_code;
4843     char *xml_buf;
4844     char *url;
4845     wmsCachePtr cache = (wmsCachePtr) cache_handle;
4846     int already_cached = 0;
4847     int retcode = 0;
4848 
4849 /* initializes the dynamically growing buffers */
4850     wmsMemBufferInitialize (&headerBuf);
4851     wmsMemBufferInitialize (&bodyBuf);
4852     url =
4853 	sqlite3_mprintf ("%srequest=GetTileService",
4854 			 capabilities->GetTileServiceURLGet);
4855 
4856     if (cache != NULL)
4857       {
4858 	  /* checks if it's already stored into the WMS Cache */
4859 	  wmsCachedCapabilitiesPtr cachedCapab =
4860 	      getWmsCachedCapabilities (cache, url);
4861 	  if (cachedCapab != NULL)
4862 	    {
4863 		/* ok, found from WMS Cache */
4864 		xml_buf =
4865 		    clean_xml_str ((const char *) (cachedCapab->Response));
4866 		already_cached = 1;
4867 		goto do_tile_service;
4868 	    }
4869       }
4870 
4871     curl = curl_easy_init ();
4872     if (curl)
4873       {
4874 	  /* setting the URL */
4875 	  curl_easy_setopt (curl, CURLOPT_URL, url);
4876 
4877 	  if (proxy != NULL)
4878 	    {
4879 		/* setting up the required proxy */
4880 		curl_easy_setopt (curl, CURLOPT_PROXY, proxy);
4881 	    }
4882 
4883 	  /* no progress meter please */
4884 	  curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1L);
4885 	  /* setting the output callback function */
4886 	  curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, store_data);
4887 	  curl_easy_setopt (curl, CURLOPT_WRITEHEADER, &headerBuf);
4888 	  curl_easy_setopt (curl, CURLOPT_WRITEDATA, &bodyBuf);
4889 
4890 	  /* Perform the request, res will get the return code */
4891 	  res = curl_easy_perform (curl);
4892 	  /* Check for errors */
4893 	  if (res != CURLE_OK)
4894 	    {
4895 		fprintf (stderr, "CURL error: %s\n", curl_easy_strerror (res));
4896 		goto stop;
4897 	    }
4898 
4899 	  /* verifying the HTTP status code */
4900 	  check_http_header (&headerBuf, &http_status, &http_code);
4901 	  if (http_status != 200)
4902 	    {
4903 		fprintf (stderr, "Invalid HTTP status code: %d %s\n",
4904 			 http_status, http_code);
4905 		if (http_code != NULL)
4906 		    free (http_code);
4907 		goto stop;
4908 	    }
4909 	  if (http_code != NULL)
4910 	      free (http_code);
4911       }
4912 
4913     /* attempting to parse the GetCapabilities answer */
4914     xml_buf = clean_xml (&bodyBuf);
4915   do_tile_service:
4916     if (xml_buf != NULL)
4917       {
4918 	  parse_wms_get_tile_service (capabilities, xml_buf);
4919 	  free (xml_buf);
4920 	  retcode = 1;
4921       }
4922     if (!already_cached)
4923       {
4924 	  /* saving into the WMS Cache */
4925 	  wmsAddCachedCapabilities (cache, url, bodyBuf.Buffer,
4926 				    bodyBuf.WriteOffset);
4927       }
4928 
4929     /* memory cleanup */
4930   stop:
4931     wmsMemBufferReset (&headerBuf);
4932     wmsMemBufferReset (&bodyBuf);
4933     sqlite3_free (url);
4934     if (curl != NULL)
4935 	curl_easy_cleanup (curl);
4936     return retcode;
4937 }
4938 
4939 RL2_DECLARE rl2WmsCatalogPtr
create_wms_catalog(rl2WmsCachePtr cache_handle,const char * url,const char * proxy,char ** err_msg)4940 create_wms_catalog (rl2WmsCachePtr cache_handle, const char *url,
4941 		    const char *proxy, char **err_msg)
4942 {
4943 /* attempting to get and parse a WMS GetCapabilities request */
4944     CURL *curl = NULL;
4945     CURLcode res;
4946     wmsMemBuffer headerBuf;
4947     wmsMemBuffer bodyBuf;
4948     int http_status;
4949     char *http_code;
4950     wmsCapabilitiesPtr capabilities = NULL;
4951     char *xml_buf;
4952     wmsCachePtr cache = (wmsCachePtr) cache_handle;
4953     int already_cached = 0;
4954 
4955 /* initializes the dynamically growing buffers */
4956     wmsMemBufferInitialize (&headerBuf);
4957     wmsMemBufferInitialize (&bodyBuf);
4958 
4959     if (cache != NULL)
4960       {
4961 	  /* checks if it's already stored into the WMS Cache */
4962 	  wmsCachedCapabilitiesPtr cachedCapab =
4963 	      getWmsCachedCapabilities (cache, url);
4964 	  if (cachedCapab != NULL)
4965 	    {
4966 		/* ok, found from WMS Cache */
4967 		xml_buf =
4968 		    clean_xml_str ((const char *) (cachedCapab->Response));
4969 		already_cached = 1;
4970 		goto do_capabilities;
4971 	    }
4972       }
4973 
4974     *err_msg = NULL;
4975     curl = curl_easy_init ();
4976     if (curl)
4977       {
4978 	  /* setting the URL */
4979 	  curl_easy_setopt (curl, CURLOPT_URL, url);
4980 
4981 	  if (proxy != NULL)
4982 	    {
4983 		/* setting up the required proxy */
4984 		curl_easy_setopt (curl, CURLOPT_PROXY, proxy);
4985 	    }
4986 
4987 	  /* no progress meter please */
4988 	  curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1L);
4989 	  /* setting the output callback function */
4990 	  curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, store_data);
4991 	  curl_easy_setopt (curl, CURLOPT_WRITEHEADER, &headerBuf);
4992 	  curl_easy_setopt (curl, CURLOPT_WRITEDATA, &bodyBuf);
4993 
4994 	  /* Perform the request, res will get the return code */
4995 	  res = curl_easy_perform (curl);
4996 	  /* Check for errors */
4997 	  if (res != CURLE_OK)
4998 	    {
4999 		fprintf (stderr, "CURL error: %s\n", curl_easy_strerror (res));
5000 		goto stop;
5001 	    }
5002 
5003 	  /* verifying the HTTP status code */
5004 	  check_http_header (&headerBuf, &http_status, &http_code);
5005 	  if (http_status != 200)
5006 	    {
5007 		fprintf (stderr, "Invalid HTTP status code: %d %s\n",
5008 			 http_status, http_code);
5009 		if (http_code != NULL)
5010 		    free (http_code);
5011 		goto stop;
5012 	    }
5013 	  if (http_code != NULL)
5014 	      free (http_code);
5015 
5016 	  /* attempting to parse the GetCapabilities answer */
5017 	  xml_buf = clean_xml (&bodyBuf);
5018 	do_capabilities:
5019 	  if (xml_buf != NULL)
5020 	    {
5021 		capabilities = parse_wms_capabilities (xml_buf);
5022 		free (xml_buf);
5023 	    }
5024 
5025 	  if (capabilities != NULL)
5026 	    {
5027 		if (capabilities->GetTileServiceURLGet != NULL)
5028 		  {
5029 		      /* attempting to resolve WMS GetTileService */
5030 		      int retry = 0;
5031 		      /* first attempt */
5032 		      if (!query_TileService
5033 			  (cache_handle, capabilities, proxy))
5034 			  retry = 1;
5035 		      if (retry)
5036 			{
5037 			    /* second attempt */
5038 			    retry = 0;
5039 			    if (!query_TileService
5040 				(cache_handle, capabilities, proxy))
5041 				retry = 1;
5042 			}
5043 		      if (retry)
5044 			{
5045 			    /* third attempt */
5046 			    retry = 0;
5047 			    if (!query_TileService
5048 				(cache_handle, capabilities, proxy))
5049 				retry = 1;
5050 			}
5051 		      if (retry)
5052 			{
5053 			    /* fourth attempt */
5054 			    retry = 0;
5055 			    if (!query_TileService
5056 				(cache_handle, capabilities, proxy))
5057 				retry = 1;
5058 			}
5059 		      if (retry)
5060 			{
5061 			    /* fifth attempt */
5062 			    if (!query_TileService
5063 				(cache_handle, capabilities, proxy))
5064 			      {
5065 				  /* giving up */
5066 				  wmsFreeCapabilities (capabilities);
5067 				  capabilities = NULL;
5068 				  goto stop;
5069 			      }
5070 			}
5071 		  }
5072 		if (!already_cached)
5073 		  {
5074 		      /* saving into the WMS Cache */
5075 		      wmsAddCachedCapabilities (cache, url, bodyBuf.Buffer,
5076 						bodyBuf.WriteOffset);
5077 		  }
5078 	    }
5079       }
5080 
5081   stop:
5082     if (curl != NULL)
5083 	curl_easy_cleanup (curl);
5084     wmsMemBufferReset (&headerBuf);
5085     wmsMemBufferReset (&bodyBuf);
5086     return (rl2WmsCatalogPtr) capabilities;
5087 }
5088 
5089 RL2_DECLARE void
destroy_wms_catalog(rl2WmsCatalogPtr handle)5090 destroy_wms_catalog (rl2WmsCatalogPtr handle)
5091 {
5092 /* memory cleanup: freeing a WMS-Catalog object */
5093     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5094     if (ptr == NULL)
5095 	return;
5096     wmsFreeCapabilities (ptr);
5097 }
5098 
5099 RL2_DECLARE int
get_wms_format_count(rl2WmsCatalogPtr handle,int mode)5100 get_wms_format_count (rl2WmsCatalogPtr handle, int mode)
5101 {
5102 /* counting how many Formats are supported by a WMS-Catalog */
5103     int count = 0;
5104     wmsFormatPtr fmt;
5105     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5106     if (ptr == NULL)
5107 	return -1;
5108 
5109     fmt = ptr->firstFormat;
5110     while (fmt != NULL)
5111       {
5112 	  if (mode)
5113 	    {
5114 		if (fmt->FormatCode != WMS_FORMAT_UNKNOWN)
5115 		    count++;
5116 	    }
5117 	  else
5118 	      count++;
5119 	  fmt = fmt->next;
5120       }
5121     return count;
5122 }
5123 
5124 RL2_DECLARE const char *
get_wms_format(rl2WmsCatalogPtr handle,int index,int mode)5125 get_wms_format (rl2WmsCatalogPtr handle, int index, int mode)
5126 {
5127 /* attempting to get the Nth Format supported by some WMS-Catalog object */
5128     int count = 0;
5129     wmsFormatPtr fmt;
5130     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5131     if (ptr == NULL)
5132 	return NULL;
5133 
5134     fmt = ptr->firstFormat;
5135     while (fmt != NULL)
5136       {
5137 	  if (mode)
5138 	    {
5139 		if (fmt->FormatCode == WMS_FORMAT_UNKNOWN)
5140 		  {
5141 		      fmt = fmt->next;
5142 		      continue;
5143 		  }
5144 	    }
5145 	  if (count == index)
5146 	      return fmt->Format;
5147 	  count++;
5148 	  fmt = fmt->next;
5149       }
5150     return NULL;
5151 }
5152 
5153 RL2_DECLARE const char *
get_wms_contact_person(rl2WmsCatalogPtr handle)5154 get_wms_contact_person (rl2WmsCatalogPtr handle)
5155 {
5156 /* attempting to get the Contact Person defined by some WMS-Catalog object */
5157     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5158     if (ptr == NULL)
5159 	return NULL;
5160 
5161     return ptr->ContactPerson;
5162 }
5163 
5164 RL2_DECLARE const char *
get_wms_contact_organization(rl2WmsCatalogPtr handle)5165 get_wms_contact_organization (rl2WmsCatalogPtr handle)
5166 {
5167 /* attempting to get the Contact Organization defined by some WMS-Catalog object */
5168     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5169     if (ptr == NULL)
5170 	return NULL;
5171 
5172     return ptr->ContactOrganization;
5173 }
5174 
5175 RL2_DECLARE const char *
get_wms_contact_position(rl2WmsCatalogPtr handle)5176 get_wms_contact_position (rl2WmsCatalogPtr handle)
5177 {
5178 /* attempting to get the Contact Position defined by some WMS-Catalog object */
5179     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5180     if (ptr == NULL)
5181 	return NULL;
5182 
5183     return ptr->ContactPosition;
5184 }
5185 
5186 RL2_DECLARE const char *
get_wms_contact_postal_address(rl2WmsCatalogPtr handle)5187 get_wms_contact_postal_address (rl2WmsCatalogPtr handle)
5188 {
5189 /* attempting to get the Postal Address defined by some WMS-Catalog object */
5190     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5191     if (ptr == NULL)
5192 	return NULL;
5193 
5194     return ptr->PostalAddress;
5195 }
5196 
5197 RL2_DECLARE const char *
get_wms_contact_city(rl2WmsCatalogPtr handle)5198 get_wms_contact_city (rl2WmsCatalogPtr handle)
5199 {
5200 /* attempting to get the City (Postal Address) defined by some WMS-Catalog object */
5201     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5202     if (ptr == NULL)
5203 	return NULL;
5204 
5205     return ptr->City;
5206 }
5207 
5208 RL2_DECLARE const char *
get_wms_contact_state_province(rl2WmsCatalogPtr handle)5209 get_wms_contact_state_province (rl2WmsCatalogPtr handle)
5210 {
5211 /* attempting to get the State or Province (Postal Address) defined by some WMS-Catalog object */
5212     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5213     if (ptr == NULL)
5214 	return NULL;
5215 
5216     return ptr->StateProvince;
5217 }
5218 
5219 RL2_DECLARE const char *
get_wms_contact_post_code(rl2WmsCatalogPtr handle)5220 get_wms_contact_post_code (rl2WmsCatalogPtr handle)
5221 {
5222 /* attempting to get the Post Code (Postal Address) defined by some WMS-Catalog object */
5223     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5224     if (ptr == NULL)
5225 	return NULL;
5226 
5227     return ptr->PostCode;
5228 }
5229 
5230 RL2_DECLARE const char *
get_wms_contact_country(rl2WmsCatalogPtr handle)5231 get_wms_contact_country (rl2WmsCatalogPtr handle)
5232 {
5233 /* attempting to get the Country (Postal Address) defined by some WMS-Catalog object */
5234     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5235     if (ptr == NULL)
5236 	return NULL;
5237 
5238     return ptr->Country;
5239 }
5240 
5241 RL2_DECLARE const char *
get_wms_contact_voice_telephone(rl2WmsCatalogPtr handle)5242 get_wms_contact_voice_telephone (rl2WmsCatalogPtr handle)
5243 {
5244 /* attempting to get the Voice Telephone defined by some WMS-Catalog object */
5245     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5246     if (ptr == NULL)
5247 	return NULL;
5248 
5249     return ptr->VoiceTelephone;
5250 }
5251 
5252 RL2_DECLARE const char *
get_wms_contact_fax_telephone(rl2WmsCatalogPtr handle)5253 get_wms_contact_fax_telephone (rl2WmsCatalogPtr handle)
5254 {
5255 /* attempting to get the FAX Telephone defined by some WMS-Catalog object */
5256     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5257     if (ptr == NULL)
5258 	return NULL;
5259 
5260     return ptr->FaxTelephone;
5261 }
5262 
5263 RL2_DECLARE const char *
get_wms_contact_email_address(rl2WmsCatalogPtr handle)5264 get_wms_contact_email_address (rl2WmsCatalogPtr handle)
5265 {
5266 /* attempting to get the e-mail Address defined by some WMS-Catalog object */
5267     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5268     if (ptr == NULL)
5269 	return NULL;
5270 
5271     return ptr->EMailAddress;
5272 }
5273 
5274 RL2_DECLARE const char *
get_wms_fees(rl2WmsCatalogPtr handle)5275 get_wms_fees (rl2WmsCatalogPtr handle)
5276 {
5277 /* attempting to get the Fees required by some WMS-Catalog object */
5278     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5279     if (ptr == NULL)
5280 	return NULL;
5281 
5282     return ptr->Fees;
5283 }
5284 
5285 RL2_DECLARE const char *
get_wms_access_constraints(rl2WmsCatalogPtr handle)5286 get_wms_access_constraints (rl2WmsCatalogPtr handle)
5287 {
5288 /* attempting to get the Access Constraints imposed by some WMS-Catalog object */
5289     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5290     if (ptr == NULL)
5291 	return NULL;
5292 
5293     return ptr->AccessConstraints;
5294 }
5295 
5296 RL2_DECLARE int
get_wms_layer_limit(rl2WmsCatalogPtr handle)5297 get_wms_layer_limit (rl2WmsCatalogPtr handle)
5298 {
5299 /* attempting to get the LayerLimit supported by some WMS-Catalog object */
5300     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5301     if (ptr == NULL)
5302 	return -1;
5303 
5304     return ptr->LayerLimit;
5305 }
5306 
5307 RL2_DECLARE int
get_wms_max_width(rl2WmsCatalogPtr handle)5308 get_wms_max_width (rl2WmsCatalogPtr handle)
5309 {
5310 /* attempting to get the MaxWidth supported by some WMS-Catalog object */
5311     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5312     if (ptr == NULL)
5313 	return -1;
5314 
5315     return ptr->MaxWidth;
5316 }
5317 
5318 RL2_DECLARE int
get_wms_max_height(rl2WmsCatalogPtr handle)5319 get_wms_max_height (rl2WmsCatalogPtr handle)
5320 {
5321 /* attempting to get the MaxHeight supported by some WMS-Catalog object */
5322     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5323     if (ptr == NULL)
5324 	return -1;
5325 
5326     return ptr->MaxHeight;
5327 }
5328 
5329 RL2_DECLARE const char *
get_wms_version(rl2WmsCatalogPtr handle)5330 get_wms_version (rl2WmsCatalogPtr handle)
5331 {
5332 /* attempting to get the Version String from some WMS-Catalog object */
5333     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5334     if (ptr == NULL)
5335 	return NULL;
5336 
5337     return ptr->Version;
5338 }
5339 
5340 RL2_DECLARE const char *
get_wms_name(rl2WmsCatalogPtr handle)5341 get_wms_name (rl2WmsCatalogPtr handle)
5342 {
5343 /* attempting to get the Name from some WMS-Catalog object */
5344     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5345     if (ptr == NULL)
5346 	return NULL;
5347 
5348     return ptr->Name;
5349 }
5350 
5351 RL2_DECLARE const char *
get_wms_title(rl2WmsCatalogPtr handle)5352 get_wms_title (rl2WmsCatalogPtr handle)
5353 {
5354 /* attempting to get the Title from some WMS-Catalog object */
5355     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5356     if (ptr == NULL)
5357 	return NULL;
5358 
5359     return ptr->Title;
5360 }
5361 
5362 RL2_DECLARE const char *
get_wms_abstract(rl2WmsCatalogPtr handle)5363 get_wms_abstract (rl2WmsCatalogPtr handle)
5364 {
5365 /* attempting to get the Abstract from some WMS-Catalog object */
5366     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5367     if (ptr == NULL)
5368 	return NULL;
5369 
5370     return ptr->Abstract;
5371 }
5372 
5373 RL2_DECLARE const char *
get_wms_url_GetMap_get(rl2WmsCatalogPtr handle)5374 get_wms_url_GetMap_get (rl2WmsCatalogPtr handle)
5375 {
5376 /* attempting to get the GetMap URL (method GET) from some WMS-Catalog object */
5377     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5378     if (ptr == NULL)
5379 	return NULL;
5380 
5381     return ptr->GetMapURLGet;
5382 }
5383 
5384 RL2_DECLARE const char *
get_wms_url_GetMap_post(rl2WmsCatalogPtr handle)5385 get_wms_url_GetMap_post (rl2WmsCatalogPtr handle)
5386 {
5387 /* attempting to get the GetMap URL (method POST) from some WMS-Catalog object */
5388     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5389     if (ptr == NULL)
5390 	return NULL;
5391 
5392     return ptr->GetMapURLPost;
5393 }
5394 
5395 RL2_DECLARE const char *
get_wms_url_GetTileService_get(rl2WmsCatalogPtr handle)5396 get_wms_url_GetTileService_get (rl2WmsCatalogPtr handle)
5397 {
5398 /* attempting to get the GetTileService URL (method GET) from some WMS-Catalog object */
5399     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5400     if (ptr == NULL)
5401 	return NULL;
5402 
5403     return ptr->GetTileServiceURLGet;
5404 }
5405 
5406 RL2_DECLARE const char *
get_wms_url_GetTileService_post(rl2WmsCatalogPtr handle)5407 get_wms_url_GetTileService_post (rl2WmsCatalogPtr handle)
5408 {
5409 /* attempting to get the GetTileService URL (method POST) from some WMS-Catalog object */
5410     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5411     if (ptr == NULL)
5412 	return NULL;
5413 
5414     return ptr->GetTileServiceURLPost;
5415 }
5416 
5417 RL2_DECLARE const char *
get_wms_url_GetFeatureInfo_get(rl2WmsCatalogPtr handle)5418 get_wms_url_GetFeatureInfo_get (rl2WmsCatalogPtr handle)
5419 {
5420 /* attempting to get the GetFeatureInfo URL (method GET) from some WMS-Catalog object */
5421     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5422     if (ptr == NULL)
5423 	return NULL;
5424 
5425     return ptr->GetFeatureInfoURLGet;
5426 }
5427 
5428 RL2_DECLARE const char *
get_wms_url_GetFeatureInfo_post(rl2WmsCatalogPtr handle)5429 get_wms_url_GetFeatureInfo_post (rl2WmsCatalogPtr handle)
5430 {
5431 /* attempting to get the GetFeatureInfo URL (method POST) from some WMS-Catalog object */
5432     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5433     if (ptr == NULL)
5434 	return NULL;
5435 
5436     return ptr->GetFeatureInfoURLPost;
5437 }
5438 
5439 RL2_DECLARE const char *
get_wms_gml_mime_type(rl2WmsCatalogPtr handle)5440 get_wms_gml_mime_type (rl2WmsCatalogPtr handle)
5441 {
5442 /* attempting to get the GML MIME type from some WMS-Catalog object */
5443     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5444     if (ptr == NULL)
5445 	return NULL;
5446 
5447     return ptr->GmlMimeType;
5448 }
5449 
5450 RL2_DECLARE const char *
get_wms_xml_mime_type(rl2WmsCatalogPtr handle)5451 get_wms_xml_mime_type (rl2WmsCatalogPtr handle)
5452 {
5453 /* attempting to get the XML MIME type from some WMS-Catalog object */
5454     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5455     if (ptr == NULL)
5456 	return NULL;
5457 
5458     return ptr->XmlMimeType;
5459 }
5460 
5461 RL2_DECLARE int
is_wms_tile_service(rl2WmsCatalogPtr handle)5462 is_wms_tile_service (rl2WmsCatalogPtr handle)
5463 {
5464 /* testing if a WMS-Catalog actually is a TileService */
5465     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5466     if (ptr == NULL)
5467 	return -1;
5468 
5469     if (ptr->firstTiled != NULL)
5470 	return 1;
5471     return 0;
5472 }
5473 
5474 RL2_DECLARE const char *
get_wms_tile_service_name(rl2WmsCatalogPtr handle)5475 get_wms_tile_service_name (rl2WmsCatalogPtr handle)
5476 {
5477 /* return the TileService name */
5478     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5479     if (ptr == NULL)
5480 	return NULL;
5481 
5482     return ptr->TileServiceName;
5483 }
5484 
5485 RL2_DECLARE const char *
get_wms_tile_service_title(rl2WmsCatalogPtr handle)5486 get_wms_tile_service_title (rl2WmsCatalogPtr handle)
5487 {
5488 /* return the TileService title */
5489     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5490     if (ptr == NULL)
5491 	return NULL;
5492 
5493     return ptr->TileServiceTitle;
5494 }
5495 
5496 RL2_DECLARE const char *
get_wms_tile_service_abstract(rl2WmsCatalogPtr handle)5497 get_wms_tile_service_abstract (rl2WmsCatalogPtr handle)
5498 {
5499 /* return the TileService abstract */
5500     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5501     if (ptr == NULL)
5502 	return NULL;
5503 
5504     return ptr->TileServiceAbstract;
5505 }
5506 
5507 RL2_DECLARE int
get_wms_tile_service_count(rl2WmsCatalogPtr handle)5508 get_wms_tile_service_count (rl2WmsCatalogPtr handle)
5509 {
5510 /* counting how many first-level tiled layers are defined within a WMS-Catalog */
5511     int count = 0;
5512     wmsTiledLayerPtr lyr;
5513     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5514     if (ptr == NULL)
5515 	return -1;
5516 
5517     lyr = ptr->firstTiled;
5518     while (lyr != NULL)
5519       {
5520 	  count++;
5521 	  lyr = lyr->next;
5522       }
5523     return count;
5524 }
5525 
5526 RL2_DECLARE rl2WmsTiledLayerPtr
get_wms_catalog_tiled_layer(rl2WmsCatalogPtr handle,int index)5527 get_wms_catalog_tiled_layer (rl2WmsCatalogPtr handle, int index)
5528 {
5529 /* attempting to get a reference to some WMS-TiledLayer object */
5530     int count = 0;
5531     wmsTiledLayerPtr lyr;
5532     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
5533     if (ptr == NULL)
5534 	return NULL;
5535 
5536     lyr = ptr->firstTiled;
5537     while (lyr != NULL)
5538       {
5539 	  if (count == index)
5540 	      return (rl2WmsTiledLayerPtr) lyr;
5541 	  count++;
5542 	  lyr = lyr->next;
5543       }
5544     return NULL;
5545 }
5546 
5547 RL2_DECLARE int
wms_tiled_layer_has_children(rl2WmsTiledLayerPtr handle)5548 wms_tiled_layer_has_children (rl2WmsTiledLayerPtr handle)
5549 {
5550 /* testing if a WMS-TiledLayer object has TiledLayer children */
5551     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5552     if (ptr == NULL)
5553 	return 0;
5554     if (ptr->firstChild == NULL)
5555 	return 0;
5556     return 1;
5557 }
5558 
5559 RL2_DECLARE int
get_wms_tiled_layer_children_count(rl2WmsTiledLayerPtr handle)5560 get_wms_tiled_layer_children_count (rl2WmsTiledLayerPtr handle)
5561 {
5562 /* counting how many children tiled layers are defined within a WMS-TiledLayer */
5563     int count = 0;
5564     wmsTiledLayerPtr lyr;
5565     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5566     if (ptr == NULL)
5567 	return -1;
5568 
5569     lyr = ptr->firstChild;
5570     while (lyr != NULL)
5571       {
5572 	  count++;
5573 	  lyr = lyr->next;
5574       }
5575     return count;
5576 }
5577 
5578 RL2_DECLARE rl2WmsTiledLayerPtr
get_wms_child_tiled_layer(rl2WmsTiledLayerPtr handle,int index)5579 get_wms_child_tiled_layer (rl2WmsTiledLayerPtr handle, int index)
5580 {
5581 /* attempting to get a reference to some child WMS-TiledLayer object */
5582     int count = 0;
5583     wmsTiledLayerPtr lyr;
5584     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5585     if (ptr == NULL)
5586 	return NULL;
5587 
5588     lyr = ptr->firstChild;
5589     while (lyr != NULL)
5590       {
5591 	  if (count == index)
5592 	      return (rl2WmsTiledLayerPtr) lyr;
5593 	  count++;
5594 	  lyr = lyr->next;
5595       }
5596     return NULL;
5597 }
5598 
5599 RL2_DECLARE const char *
get_wms_tiled_layer_name(rl2WmsTiledLayerPtr handle)5600 get_wms_tiled_layer_name (rl2WmsTiledLayerPtr handle)
5601 {
5602 /* return the name corresponding to a WMS-TiledLayer object */
5603     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5604     if (ptr == NULL)
5605 	return NULL;
5606     return ptr->Name;
5607 }
5608 
5609 RL2_DECLARE const char *
get_wms_tiled_layer_title(rl2WmsTiledLayerPtr handle)5610 get_wms_tiled_layer_title (rl2WmsTiledLayerPtr handle)
5611 {
5612 /* return the title corresponding to a WMS-TiledLayer object */
5613     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5614     if (ptr == NULL)
5615 	return NULL;
5616     return ptr->Title;
5617 }
5618 
5619 RL2_DECLARE const char *
get_wms_tiled_layer_abstract(rl2WmsTiledLayerPtr handle)5620 get_wms_tiled_layer_abstract (rl2WmsTiledLayerPtr handle)
5621 {
5622 /* return the abstract corresponding to a WMS-TiledLayer object */
5623     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5624     if (ptr == NULL)
5625 	return NULL;
5626     return ptr->Abstract;
5627 }
5628 
5629 RL2_DECLARE const char *
get_wms_tiled_layer_pad(rl2WmsTiledLayerPtr handle)5630 get_wms_tiled_layer_pad (rl2WmsTiledLayerPtr handle)
5631 {
5632 /* return the Pad corresponding to a WMS-TiledLayer object */
5633     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5634     if (ptr == NULL)
5635 	return NULL;
5636     return ptr->Pad;
5637 }
5638 
5639 RL2_DECLARE const char *
get_wms_tiled_layer_bands(rl2WmsTiledLayerPtr handle)5640 get_wms_tiled_layer_bands (rl2WmsTiledLayerPtr handle)
5641 {
5642 /* return the Bands corresponding to a WMS-TiledLayer object */
5643     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5644     if (ptr == NULL)
5645 	return NULL;
5646     return ptr->Bands;
5647 }
5648 
5649 RL2_DECLARE const char *
get_wms_tiled_layer_data_type(rl2WmsTiledLayerPtr handle)5650 get_wms_tiled_layer_data_type (rl2WmsTiledLayerPtr handle)
5651 {
5652 /* return the Bands corresponding to a WMS-TiledLayer object */
5653     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5654     if (ptr == NULL)
5655 	return NULL;
5656     return ptr->DataType;
5657 }
5658 
5659 RL2_DECLARE int
get_wms_tiled_layer_bbox(rl2WmsTiledLayerPtr handle,double * minx,double * miny,double * maxx,double * maxy)5660 get_wms_tiled_layer_bbox (rl2WmsTiledLayerPtr handle, double *minx,
5661 			  double *miny, double *maxx, double *maxy)
5662 {
5663 /* return the BBox corresponding to a WMS-TiledLayer object */
5664     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5665     if (ptr == NULL)
5666 	return 0;
5667     *minx = ptr->MinLong;
5668     *miny = ptr->MinLat;
5669     *maxx = ptr->MaxLong;
5670     *maxy = ptr->MaxLat;
5671     return 1;
5672 }
5673 
5674 RL2_DECLARE int
get_wms_tiled_layer_tile_size(rl2WmsTiledLayerPtr handle,int * width,int * height)5675 get_wms_tiled_layer_tile_size (rl2WmsTiledLayerPtr handle, int *width,
5676 			       int *height)
5677 {
5678 /* return the Tile Size corresponding to a WMS-TiledLayer object */
5679     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5680     if (ptr == NULL)
5681 	return 0;
5682     if (ptr->firstPattern == NULL)
5683 	return 0;
5684     *width = ptr->firstPattern->TileWidth;
5685     *height = ptr->firstPattern->TileHeight;
5686     return 1;
5687 }
5688 
5689 RL2_DECLARE const char *
get_wms_tiled_layer_crs(rl2WmsTiledLayerPtr handle)5690 get_wms_tiled_layer_crs (rl2WmsTiledLayerPtr handle)
5691 {
5692 /* return the CRS corresponding to a WMS-TiledLayer object */
5693     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5694     if (ptr == NULL)
5695 	return NULL;
5696     if (ptr->firstPattern == NULL)
5697 	return NULL;
5698     return ptr->firstPattern->SRS;
5699 }
5700 
5701 RL2_DECLARE const char *
get_wms_tiled_layer_format(rl2WmsTiledLayerPtr handle)5702 get_wms_tiled_layer_format (rl2WmsTiledLayerPtr handle)
5703 {
5704 /* return the Format corresponding to a WMS-TiledLayer object */
5705     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5706     if (ptr == NULL)
5707 	return NULL;
5708     if (ptr->firstPattern == NULL)
5709 	return NULL;
5710     return ptr->firstPattern->Format;
5711 }
5712 
5713 RL2_DECLARE const char *
get_wms_tiled_layer_style(rl2WmsTiledLayerPtr handle)5714 get_wms_tiled_layer_style (rl2WmsTiledLayerPtr handle)
5715 {
5716 /* return the Style corresponding to a WMS-TiledLayer object */
5717     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5718     if (ptr == NULL)
5719 	return NULL;
5720     if (ptr->firstPattern == NULL)
5721 	return NULL;
5722     return ptr->firstPattern->Style;
5723 }
5724 
5725 RL2_DECLARE int
get_wms_tile_pattern_count(rl2WmsTiledLayerPtr handle)5726 get_wms_tile_pattern_count (rl2WmsTiledLayerPtr handle)
5727 {
5728 /* counting how many TilePatterns are defined within a WMS-TiledLayer object */
5729     int count = 0;
5730     wmsTilePatternPtr pattern;
5731     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5732     if (ptr == NULL)
5733 	return -1;
5734 
5735     pattern = ptr->firstPattern;
5736     while (pattern != NULL)
5737       {
5738 	  count++;
5739 	  pattern = pattern->next;
5740       }
5741     return count;
5742 }
5743 
5744 RL2_DECLARE rl2WmsTilePatternPtr
get_wms_tile_pattern_handle(rl2WmsTiledLayerPtr handle,int index)5745 get_wms_tile_pattern_handle (rl2WmsTiledLayerPtr handle, int index)
5746 {
5747 /* return the Handle from a TilePattern (identified by its index) */
5748     int count = 0;
5749     wmsTilePatternPtr pattern;
5750     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5751     if (ptr == NULL)
5752 	return NULL;
5753 
5754     pattern = ptr->firstPattern;
5755     while (pattern != NULL)
5756       {
5757 	  if (count == index)
5758 	      return (rl2WmsTilePatternPtr) pattern;
5759 	  count++;
5760 	  pattern = pattern->next;
5761       }
5762     return NULL;
5763 }
5764 
5765 RL2_DECLARE rl2WmsTilePatternPtr
clone_wms_tile_pattern(rl2WmsTilePatternPtr handle)5766 clone_wms_tile_pattern (rl2WmsTilePatternPtr handle)
5767 {
5768 /* clones a WMS TilePattern object */
5769     char *str;
5770     int len;
5771     wmsTilePatternPtr clone;
5772     wmsTilePatternPtr pattern = (wmsTilePatternPtr) handle;
5773     if (pattern == NULL)
5774 	return NULL;
5775 
5776     len = strlen (pattern->Pattern);
5777     str = malloc (len + 1);
5778     strcpy (str, pattern->Pattern);
5779     clone = wmsAllocTilePattern (str);
5780     return (rl2WmsTilePatternPtr) clone;
5781 }
5782 
5783 RL2_DECLARE void
destroy_wms_tile_pattern(rl2WmsTilePatternPtr handle)5784 destroy_wms_tile_pattern (rl2WmsTilePatternPtr handle)
5785 {
5786 /* memory cleanup - finalizes a WMS-TilePattern object */
5787     wmsTilePatternPtr pattern = (wmsTilePatternPtr) handle;
5788     if (pattern == NULL)
5789 	return;
5790     wmsFreeTilePattern (pattern);
5791 }
5792 
5793 RL2_DECLARE const char *
get_wms_tile_pattern_srs(rl2WmsTiledLayerPtr handle,int index)5794 get_wms_tile_pattern_srs (rl2WmsTiledLayerPtr handle, int index)
5795 {
5796 /* return the SRS from a TilePattern (identified by its index) */
5797     int count = 0;
5798     wmsTilePatternPtr pattern;
5799     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5800     if (ptr == NULL)
5801 	return NULL;
5802 
5803     pattern = ptr->firstPattern;
5804     while (pattern != NULL)
5805       {
5806 	  if (count == index)
5807 	      return pattern->SRS;
5808 	  count++;
5809 	  pattern = pattern->next;
5810       }
5811     return NULL;
5812 }
5813 
5814 RL2_DECLARE int
get_wms_tile_pattern_tile_width(rl2WmsTiledLayerPtr handle,int index)5815 get_wms_tile_pattern_tile_width (rl2WmsTiledLayerPtr handle, int index)
5816 {
5817 /* return the TileWidth from a TilePattern (identified by its index) */
5818     int count = 0;
5819     wmsTilePatternPtr pattern;
5820     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5821     if (ptr == NULL)
5822 	return -1;
5823 
5824     pattern = ptr->firstPattern;
5825     while (pattern != NULL)
5826       {
5827 	  if (count == index)
5828 	      return pattern->TileWidth;
5829 	  count++;
5830 	  pattern = pattern->next;
5831       }
5832     return -1;
5833 }
5834 
5835 RL2_DECLARE int
get_wms_tile_pattern_tile_height(rl2WmsTiledLayerPtr handle,int index)5836 get_wms_tile_pattern_tile_height (rl2WmsTiledLayerPtr handle, int index)
5837 {
5838 /* return the TileHeight from a TilePattern (identified by its index) */
5839     int count = 0;
5840     wmsTilePatternPtr pattern;
5841     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5842     if (ptr == NULL)
5843 	return -1;
5844 
5845     pattern = ptr->firstPattern;
5846     while (pattern != NULL)
5847       {
5848 	  if (count == index)
5849 	      return pattern->TileHeight;
5850 	  count++;
5851 	  pattern = pattern->next;
5852       }
5853     return -1;
5854 }
5855 
5856 RL2_DECLARE double
get_wms_tile_pattern_base_x(rl2WmsTiledLayerPtr handle,int index)5857 get_wms_tile_pattern_base_x (rl2WmsTiledLayerPtr handle, int index)
5858 {
5859 /* return the TileBaseX (leftmost coord) from a TilePattern (identified by its index) */
5860     int count = 0;
5861     wmsTilePatternPtr pattern;
5862     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5863     if (ptr == NULL)
5864 	return DBL_MAX;
5865 
5866     pattern = ptr->firstPattern;
5867     while (pattern != NULL)
5868       {
5869 	  if (count == index)
5870 	      return pattern->TileBaseX;
5871 	  count++;
5872 	  pattern = pattern->next;
5873       }
5874     return DBL_MAX;
5875 }
5876 
5877 RL2_DECLARE double
get_wms_tile_pattern_base_y(rl2WmsTiledLayerPtr handle,int index)5878 get_wms_tile_pattern_base_y (rl2WmsTiledLayerPtr handle, int index)
5879 {
5880 /* return the TileBaseY (topmost coord) from a TilePattern (identified by its index) */
5881     int count = 0;
5882     wmsTilePatternPtr pattern;
5883     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5884     if (ptr == NULL)
5885 	return DBL_MAX;
5886 
5887     pattern = ptr->firstPattern;
5888     while (pattern != NULL)
5889       {
5890 	  if (count == index)
5891 	      return pattern->TileBaseY;
5892 	  count++;
5893 	  pattern = pattern->next;
5894       }
5895     return DBL_MAX;
5896 }
5897 
5898 RL2_DECLARE double
get_wms_tile_pattern_extent_x(rl2WmsTiledLayerPtr handle,int index)5899 get_wms_tile_pattern_extent_x (rl2WmsTiledLayerPtr handle, int index)
5900 {
5901 /* return the TileExtentX from a TilePattern (identified by its index) */
5902     int count = 0;
5903     wmsTilePatternPtr pattern;
5904     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5905     if (ptr == NULL)
5906 	return DBL_MAX;
5907 
5908     pattern = ptr->firstPattern;
5909     while (pattern != NULL)
5910       {
5911 	  if (count == index)
5912 	      return pattern->TileExtentX;
5913 	  count++;
5914 	  pattern = pattern->next;
5915       }
5916     return DBL_MAX;
5917 }
5918 
5919 RL2_DECLARE double
get_wms_tile_pattern_extent_y(rl2WmsTiledLayerPtr handle,int index)5920 get_wms_tile_pattern_extent_y (rl2WmsTiledLayerPtr handle, int index)
5921 {
5922 /* return the TileExtentY from a TilePattern (identified by its index) */
5923     int count = 0;
5924     wmsTilePatternPtr pattern;
5925     wmsTiledLayerPtr ptr = (wmsTiledLayerPtr) handle;
5926     if (ptr == NULL)
5927 	return DBL_MAX;
5928 
5929     pattern = ptr->firstPattern;
5930     while (pattern != NULL)
5931       {
5932 	  if (count == index)
5933 	      return pattern->TileExtentY;
5934 	  count++;
5935 	  pattern = pattern->next;
5936       }
5937     return DBL_MAX;
5938 }
5939 
5940 RL2_DECLARE char *
get_wms_tile_pattern_sample_url(rl2WmsTilePatternPtr handle)5941 get_wms_tile_pattern_sample_url (rl2WmsTilePatternPtr handle)
5942 {
5943 /* return the sample URL for some TilePattern */
5944     char *url = NULL;
5945     wmsUrlArgumentPtr arg;
5946     wmsTilePatternPtr ptr = (wmsTilePatternPtr) handle;
5947     if (ptr == NULL)
5948 	return NULL;
5949 
5950     arg = ptr->first;
5951     while (arg != NULL)
5952       {
5953 	  if (url != NULL)
5954 	    {
5955 		char *str;
5956 		if (arg->argValue == NULL)
5957 		    str = sqlite3_mprintf ("%s&%s=", url, arg->argName);
5958 		else
5959 		    str =
5960 			sqlite3_mprintf ("%s&%s=%s", url,
5961 					 arg->argName, arg->argValue);
5962 		sqlite3_free (url);
5963 		url = str;
5964 	    }
5965 	  else
5966 	    {
5967 		if (arg->argValue == NULL)
5968 		    url = sqlite3_mprintf ("%s=", arg->argName);
5969 		else
5970 		    url =
5971 			sqlite3_mprintf ("%s=%s", arg->argName, arg->argValue);
5972 	    }
5973 	  arg = arg->next;
5974       }
5975     return url;
5976 }
5977 
5978 RL2_DECLARE char *
get_wms_tile_pattern_request_url(rl2WmsTilePatternPtr handle,const char * base_url,double min_x,double min_y)5979 get_wms_tile_pattern_request_url (rl2WmsTilePatternPtr
5980 				  handle,
5981 				  const char *base_url,
5982 				  double min_x, double min_y)
5983 {
5984 /* return a full GetMap request URL for some TilePattern */
5985     char *url = NULL;
5986     wmsUrlArgumentPtr arg;
5987     wmsTilePatternPtr ptr = (wmsTilePatternPtr) handle;
5988     if (ptr == NULL)
5989 	return NULL;
5990 
5991     url = sqlite3_mprintf ("%s", base_url);
5992     arg = ptr->first;
5993     while (arg != NULL)
5994       {
5995 	  char *str;
5996 	  if (strcasecmp (arg->argName, "bbox") == 0)
5997 	    {
5998 		char *bbox =
5999 		    sqlite3_mprintf ("%1.6f,%1.6f,%1.6f,%1.6f", min_x, min_y,
6000 				     min_x + ptr->TileExtentX,
6001 				     min_y + ptr->TileExtentY);
6002 		if (arg != ptr->first)
6003 		  {
6004 		      str = sqlite3_mprintf ("%s&%s=%s", url,
6005 					     arg->argName, bbox);
6006 		  }
6007 		else
6008 		  {
6009 		      str =
6010 			  sqlite3_mprintf ("%s%s=%s", url, arg->argName, bbox);
6011 		  }
6012 		sqlite3_free (bbox);
6013 	    }
6014 	  else
6015 	    {
6016 		if (arg != ptr->first)
6017 		  {
6018 		      if (arg->argValue == NULL)
6019 			  str = sqlite3_mprintf ("%s&%s=", url, arg->argName);
6020 		      else
6021 			  str =
6022 			      sqlite3_mprintf ("%s&%s=%s", url,
6023 					       arg->argName, arg->argValue);
6024 		  }
6025 		else
6026 		  {
6027 		      if (arg->argValue == NULL)
6028 			  str = sqlite3_mprintf ("%s%s=", url, arg->argName);
6029 		      else
6030 			  str =
6031 			      sqlite3_mprintf ("%s%s=%s", url, arg->argName,
6032 					       arg->argValue);
6033 		  }
6034 	    }
6035 	  sqlite3_free (url);
6036 	  url = str;
6037 	  arg = arg->next;
6038       }
6039     return url;
6040 }
6041 
6042 RL2_DECLARE int
get_wms_catalog_count(rl2WmsCatalogPtr handle)6043 get_wms_catalog_count (rl2WmsCatalogPtr handle)
6044 {
6045 /* counting how many first-level layers are defined within a WMS-Catalog */
6046     int count = 0;
6047     wmsLayerPtr lyr;
6048     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
6049     if (ptr == NULL)
6050 	return -1;
6051 
6052     lyr = ptr->firstLayer;
6053     while (lyr != NULL)
6054       {
6055 	  count++;
6056 	  lyr = lyr->next;
6057       }
6058     return count;
6059 }
6060 
6061 RL2_DECLARE rl2WmsLayerPtr
get_wms_catalog_layer(rl2WmsCatalogPtr handle,int index)6062 get_wms_catalog_layer (rl2WmsCatalogPtr handle, int index)
6063 {
6064 /* attempting to get a reference to some WMS-Layer object */
6065     int count = 0;
6066     wmsLayerPtr lyr;
6067     wmsCapabilitiesPtr ptr = (wmsCapabilitiesPtr) handle;
6068     if (ptr == NULL)
6069 	return NULL;
6070 
6071     lyr = ptr->firstLayer;
6072     while (lyr != NULL)
6073       {
6074 	  if (count == index)
6075 	      return (rl2WmsLayerPtr) lyr;
6076 	  count++;
6077 	  lyr = lyr->next;
6078       }
6079     return NULL;
6080 }
6081 
6082 RL2_DECLARE int
wms_layer_has_children(rl2WmsLayerPtr handle)6083 wms_layer_has_children (rl2WmsLayerPtr handle)
6084 {
6085 /* testing if a WMS-Layer object has Layer children */
6086     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6087     if (ptr == NULL)
6088 	return 0;
6089     if (ptr->firstLayer == NULL)
6090 	return 0;
6091     return 1;
6092 }
6093 
6094 RL2_DECLARE int
get_wms_layer_children_count(rl2WmsLayerPtr handle)6095 get_wms_layer_children_count (rl2WmsLayerPtr handle)
6096 {
6097 /* counting how many children layers are defined within a WMS-Layer */
6098     int count = 0;
6099     wmsLayerPtr lyr;
6100     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6101     if (ptr == NULL)
6102 	return -1;
6103 
6104     lyr = ptr->firstLayer;
6105     while (lyr != NULL)
6106       {
6107 	  count++;
6108 	  lyr = lyr->next;
6109       }
6110     return count;
6111 }
6112 
6113 RL2_DECLARE rl2WmsLayerPtr
get_wms_child_layer(rl2WmsLayerPtr handle,int index)6114 get_wms_child_layer (rl2WmsLayerPtr handle, int index)
6115 {
6116 /* attempting to get a reference to some child WMS-Layer object */
6117     int count = 0;
6118     wmsLayerPtr lyr;
6119     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6120     if (ptr == NULL)
6121 	return NULL;
6122 
6123     lyr = ptr->firstLayer;
6124     while (lyr != NULL)
6125       {
6126 	  if (count == index)
6127 	      return (rl2WmsLayerPtr) lyr;
6128 	  count++;
6129 	  lyr = lyr->next;
6130       }
6131     return NULL;
6132 }
6133 
6134 RL2_DECLARE const char *
get_wms_layer_name(rl2WmsLayerPtr handle)6135 get_wms_layer_name (rl2WmsLayerPtr handle)
6136 {
6137 /* return the name corresponding to a WMS-Layer object */
6138     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6139     if (ptr == NULL)
6140 	return NULL;
6141     return ptr->Name;
6142 }
6143 
6144 RL2_DECLARE const char *
get_wms_layer_title(rl2WmsLayerPtr handle)6145 get_wms_layer_title (rl2WmsLayerPtr handle)
6146 {
6147 /* return the title corresponding to a WMS-Layer object */
6148     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6149     if (ptr == NULL)
6150 	return NULL;
6151     return ptr->Title;
6152 }
6153 
6154 RL2_DECLARE const char *
get_wms_layer_abstract(rl2WmsLayerPtr handle)6155 get_wms_layer_abstract (rl2WmsLayerPtr handle)
6156 {
6157 /* return the abstract corresponding to a WMS-Layer object */
6158     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6159     if (ptr == NULL)
6160 	return NULL;
6161     return ptr->Abstract;
6162 }
6163 
6164 static int
wms_parent_crs_count(wmsLayerPtr lyr)6165 wms_parent_crs_count (wmsLayerPtr lyr)
6166 {
6167 /* recursively counting how many CRSs are supported by a parent Layer (inheritance) */
6168     int count = 0;
6169     wmsCrsPtr crs;
6170     if (lyr == NULL)
6171 	return 0;
6172 
6173     crs = lyr->firstCrs;
6174     while (crs != NULL)
6175       {
6176 	  count++;
6177 	  crs = crs->next;
6178       }
6179     count += wms_parent_crs_count (lyr->Parent);
6180     return count;
6181 }
6182 
6183 RL2_DECLARE int
get_wms_layer_crs_count(rl2WmsLayerPtr handle)6184 get_wms_layer_crs_count (rl2WmsLayerPtr handle)
6185 {
6186 /* counting how many CRSs are supported by a WMS-Layer */
6187     int count = 0;
6188     wmsCrsPtr crs;
6189     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6190     if (ptr == NULL)
6191 	return -1;
6192 
6193     crs = ptr->firstCrs;
6194     while (crs != NULL)
6195       {
6196 	  count++;
6197 	  crs = crs->next;
6198       }
6199     count += wms_parent_crs_count (ptr->Parent);
6200     return count;
6201 }
6202 
6203 static wmsCrsPtr
wms_parent_crs(wmsLayerPtr lyr,int * cnt,int index)6204 wms_parent_crs (wmsLayerPtr lyr, int *cnt, int index)
6205 {
6206 /* recursively finding a CRS by index (inheritance) */
6207     int count = *cnt;
6208     wmsCrsPtr crs;
6209     if (lyr == NULL)
6210 	return 0;
6211 
6212     crs = lyr->firstCrs;
6213     while (crs != NULL)
6214       {
6215 	  if (count == index)
6216 	      return crs;
6217 	  count++;
6218 	  crs = crs->next;
6219       }
6220     *cnt = count;
6221     crs = wms_parent_crs (lyr->Parent, cnt, index);
6222     return crs;
6223 }
6224 
6225 RL2_DECLARE const char *
get_wms_layer_crs(rl2WmsLayerPtr handle,int index)6226 get_wms_layer_crs (rl2WmsLayerPtr handle, int index)
6227 {
6228 /* attempting to get the Nth CRS supported by some WMS-Layer object */
6229     int count = 0;
6230     wmsCrsPtr crs;
6231     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6232     if (ptr == NULL)
6233 	return NULL;
6234 
6235     crs = ptr->firstCrs;
6236     while (crs != NULL)
6237       {
6238 	  if (count == index)
6239 	      return crs->Crs;
6240 	  count++;
6241 	  crs = crs->next;
6242       }
6243     crs = wms_parent_crs (ptr->Parent, &count, index);
6244     if (crs != NULL)
6245 	return crs->Crs;
6246     return NULL;
6247 }
6248 
6249 RL2_DECLARE int
get_wms_layer_style_count(rl2WmsLayerPtr handle)6250 get_wms_layer_style_count (rl2WmsLayerPtr handle)
6251 {
6252 /* counting how many Styles are supported by a WMS-Layer */
6253     int count = 0;
6254     wmsStylePtr stl;
6255     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6256     if (ptr == NULL)
6257 	return -1;
6258 
6259     stl = ptr->firstStyle;
6260     while (stl != NULL)
6261       {
6262 	  count++;
6263 	  stl = stl->next;
6264       }
6265     return count;
6266 }
6267 
6268 RL2_DECLARE const char *
get_wms_layer_style_name(rl2WmsLayerPtr handle,int index)6269 get_wms_layer_style_name (rl2WmsLayerPtr handle, int index)
6270 {
6271 /* attempting to get the Name of the Nth Style supported by some WMS-Layer object */
6272     int count = 0;
6273     wmsStylePtr stl;
6274     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6275     if (ptr == NULL)
6276 	return NULL;
6277 
6278     stl = ptr->firstStyle;
6279     while (stl != NULL)
6280       {
6281 	  if (count == index)
6282 	      return stl->Name;
6283 	  count++;
6284 	  stl = stl->next;
6285       }
6286     return NULL;
6287 }
6288 
6289 RL2_DECLARE const char *
get_wms_layer_style_title(rl2WmsLayerPtr handle,int index)6290 get_wms_layer_style_title (rl2WmsLayerPtr handle, int index)
6291 {
6292 /* attempting to get the Title of the Nth Style supported by some WMS-Layer object */
6293     int count = 0;
6294     wmsStylePtr stl;
6295     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6296     if (ptr == NULL)
6297 	return NULL;
6298 
6299     stl = ptr->firstStyle;
6300     while (stl != NULL)
6301       {
6302 	  if (count == index)
6303 	      return stl->Title;
6304 	  count++;
6305 	  stl = stl->next;
6306       }
6307     return NULL;
6308 }
6309 
6310 RL2_DECLARE const char *
get_wms_layer_style_abstract(rl2WmsLayerPtr handle,int index)6311 get_wms_layer_style_abstract (rl2WmsLayerPtr handle, int index)
6312 {
6313 /* attempting to get the Abstract of the Nth Style supported by some WMS-Layer object */
6314     int count = 0;
6315     wmsStylePtr stl;
6316     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6317     if (ptr == NULL)
6318 	return NULL;
6319 
6320     stl = ptr->firstStyle;
6321     while (stl != NULL)
6322       {
6323 	  if (count == index)
6324 	      return stl->Abstract;
6325 	  count++;
6326 	  stl = stl->next;
6327       }
6328     return NULL;
6329 }
6330 
6331 static void
wms_parent_opaque(wmsLayerPtr lyr,int * opaque)6332 wms_parent_opaque (wmsLayerPtr lyr, int *opaque)
6333 {
6334 /* recursively testing the Opaque property from a parent Layer (inheritance) */
6335     if (lyr == NULL)
6336 	return;
6337 
6338     if (lyr->Opaque >= 0)
6339       {
6340 	  *opaque = lyr->Opaque;
6341 	  return;
6342       }
6343     wms_parent_opaque (lyr->Parent, opaque);
6344 }
6345 
6346 RL2_DECLARE int
is_wms_layer_opaque(rl2WmsLayerPtr handle)6347 is_wms_layer_opaque (rl2WmsLayerPtr handle)
6348 {
6349 /* Tests if some WMS-Layer object declares the Opaque property */
6350     int opaque = -1;
6351     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6352     if (ptr == NULL)
6353 	return -1;
6354 
6355     if (ptr->Opaque >= 0)
6356 	return ptr->Opaque;
6357     wms_parent_opaque (ptr->Parent, &opaque);
6358     return opaque;
6359 }
6360 
6361 static void
wms_parent_queryable(wmsLayerPtr lyr,int * queryable)6362 wms_parent_queryable (wmsLayerPtr lyr, int *queryable)
6363 {
6364 /* recursively testing the Queryable property from a parent Layer (inheritance) */
6365     if (lyr == NULL)
6366 	return;
6367 
6368     if (lyr->Queryable >= 0)
6369       {
6370 	  *queryable = lyr->Queryable;
6371 	  return;
6372       }
6373     wms_parent_opaque (lyr->Parent, queryable);
6374 }
6375 
6376 RL2_DECLARE int
is_wms_layer_queryable(rl2WmsLayerPtr handle)6377 is_wms_layer_queryable (rl2WmsLayerPtr handle)
6378 {
6379 /* Tests if some WMS-Layer object declares the Queryable property */
6380     int queryable = -1;
6381     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6382     if (ptr == NULL)
6383 	return -1;
6384 
6385     if (ptr->Queryable >= 0)
6386 	return ptr->Queryable;
6387     wms_parent_queryable (ptr->Parent, &queryable);
6388     return queryable;
6389 }
6390 
6391 RL2_DECLARE double
get_wms_layer_min_scale_denominator(rl2WmsLayerPtr handle)6392 get_wms_layer_min_scale_denominator (rl2WmsLayerPtr handle)
6393 {
6394 /* Return the MinScaleDenominator from some WMS-Layer object */
6395     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6396     if (ptr == NULL)
6397 	return DBL_MAX;
6398 
6399     return ptr->MinScaleDenominator;
6400 }
6401 
6402 RL2_DECLARE double
get_wms_layer_max_scale_denominator(rl2WmsLayerPtr handle)6403 get_wms_layer_max_scale_denominator (rl2WmsLayerPtr handle)
6404 {
6405 /* Return the MaxScaleDenominator from some WMS-Layer object */
6406     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6407     if (ptr == NULL)
6408 	return DBL_MAX;
6409 
6410     return ptr->MaxScaleDenominator;
6411 }
6412 
6413 RL2_DECLARE int
get_wms_layer_geo_bbox(rl2WmsLayerPtr handle,double * minx,double * maxx,double * miny,double * maxy)6414 get_wms_layer_geo_bbox (rl2WmsLayerPtr handle, double *minx, double *maxx,
6415 			double *miny, double *maxy)
6416 {
6417 /* Return the Geographic Bounding Box from some WMS-Layer object */
6418     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6419     *minx = DBL_MAX;
6420     *maxx = DBL_MAX;
6421     *miny = DBL_MAX;
6422     *maxx = DBL_MAX;
6423     if (ptr == NULL)
6424 	return 0;
6425 
6426     if (ptr->MinLat == DBL_MAX && ptr->MaxLat == DBL_MAX
6427 	&& ptr->MinLong == DBL_MAX && ptr->MaxLong == DBL_MAX)
6428       {
6429 	  /* undefined: iteratively searching its Parents */
6430 	  wmsLayerPtr parent = ptr->Parent;
6431 	  while (parent != NULL)
6432 	    {
6433 		if (parent->MinLat == DBL_MAX && parent->MaxLat == DBL_MAX
6434 		    && parent->MinLong == DBL_MAX && parent->MaxLong == DBL_MAX)
6435 		  {
6436 		      parent = parent->Parent;
6437 		      continue;
6438 		  }
6439 		*miny = parent->MinLat;
6440 		*maxy = parent->MaxLat;
6441 		*minx = parent->MinLong;
6442 		*maxx = parent->MaxLong;
6443 		return 1;
6444 	    }
6445       }
6446     *miny = ptr->MinLat;
6447     *maxy = ptr->MaxLat;
6448     *minx = ptr->MinLong;
6449     *maxx = ptr->MaxLong;
6450     return 1;
6451 }
6452 
6453 RL2_DECLARE int
get_wms_layer_bbox(rl2WmsLayerPtr handle,const char * crs,double * minx,double * maxx,double * miny,double * maxy)6454 get_wms_layer_bbox (rl2WmsLayerPtr handle, const char *crs, double *minx,
6455 		    double *maxx, double *miny, double *maxy)
6456 {
6457 /* Return the Bounding Box corresponding to given CRS from some WMS-Layer object */
6458     wmsBBoxPtr bbox;
6459     wmsLayerPtr ptr = (wmsLayerPtr) handle;
6460     wmsLayerPtr parent;
6461     *minx = DBL_MAX;
6462     *maxx = DBL_MAX;
6463     *miny = DBL_MAX;
6464     *maxx = DBL_MAX;
6465     if (ptr == NULL)
6466 	return 0;
6467 
6468     bbox = ptr->firstBBox;
6469     while (bbox != NULL)
6470       {
6471 	  if (strcmp (bbox->Crs, crs) == 0)
6472 	    {
6473 		*miny = bbox->MinY;
6474 		*maxy = bbox->MaxY;
6475 		*minx = bbox->MinX;
6476 		*maxx = bbox->MaxX;
6477 		return 1;
6478 	    }
6479 	  bbox = bbox->next;
6480       }
6481 
6482 /* not found: iteratively searching its Parents */
6483     parent = ptr->Parent;
6484     while (parent != NULL)
6485       {
6486 	  bbox = parent->firstBBox;
6487 	  while (bbox != NULL)
6488 	    {
6489 		if (strcmp (bbox->Crs, crs) == 0)
6490 		  {
6491 		      *miny = bbox->MinY;
6492 		      *maxy = bbox->MaxY;
6493 		      *minx = bbox->MinX;
6494 		      *maxx = bbox->MaxX;
6495 		      return 1;
6496 		  }
6497 		bbox = bbox->next;
6498 	    }
6499 	  parent = parent->Parent;
6500       }
6501     return 0;
6502 }
6503 
6504 RL2_DECLARE void
destroy_wms_feature_collection(rl2WmsFeatureCollectionPtr handle)6505 destroy_wms_feature_collection (rl2WmsFeatureCollectionPtr handle)
6506 {
6507 /* memory cleanup: freeing a GML Feature Collection object */
6508     wmsFeatureCollectionPtr ptr = (wmsFeatureCollectionPtr) handle;
6509     if (ptr == NULL)
6510 	return;
6511     wmsFreeFeatureCollection (ptr);
6512 }
6513 
6514 static int
check_swap(gaiaGeomCollPtr geom,double point_x,double point_y)6515 check_swap (gaiaGeomCollPtr geom, double point_x, double point_y)
6516 {
6517 /* checking if X and Y axes should be flipped */
6518     double x;
6519     double y;
6520     double z;
6521     double m;
6522     double dist;
6523     double dist_flip;
6524     gaiaPointPtr pt;
6525     gaiaLinestringPtr ln;
6526     gaiaPolygonPtr pg;
6527     pt = geom->FirstPoint;
6528     if (pt != NULL)
6529       {
6530 	  x = pt->X;
6531 	  y = pt->Y;
6532 	  goto eval;
6533       }
6534     ln = geom->FirstLinestring;
6535     if (ln != NULL)
6536       {
6537 	  if (ln->DimensionModel == GAIA_XY_Z)
6538 	    {
6539 		gaiaGetPointXYZ (ln->Coords, 0, &x, &y, &z);
6540 	    }
6541 	  else if (ln->DimensionModel == GAIA_XY_M)
6542 	    {
6543 		gaiaGetPointXYM (ln->Coords, 0, &x, &y, &m);
6544 	    }
6545 	  else if (ln->DimensionModel == GAIA_XY_Z_M)
6546 	    {
6547 		gaiaGetPointXYZM (ln->Coords, 0, &x, &y, &z, &m);
6548 	    }
6549 	  else
6550 	    {
6551 		gaiaGetPoint (ln->Coords, 0, &x, &y);
6552 	    }
6553 	  goto eval;
6554       }
6555     pg = geom->FirstPolygon;
6556     if (pg != NULL)
6557       {
6558 	  gaiaRingPtr ring = pg->Exterior;
6559 	  if (ring->DimensionModel == GAIA_XY_Z)
6560 	    {
6561 		gaiaGetPointXYZ (ring->Coords, 0, &x, &y, &z);
6562 	    }
6563 	  else if (ring->DimensionModel == GAIA_XY_M)
6564 	    {
6565 		gaiaGetPointXYM (ring->Coords, 0, &x, &y, &m);
6566 	    }
6567 	  else if (ring->DimensionModel == GAIA_XY_Z_M)
6568 	    {
6569 		gaiaGetPointXYZM (ring->Coords, 0, &x, &y, &z, &m);
6570 	    }
6571 	  else
6572 	    {
6573 		gaiaGetPoint (ring->Coords, 0, &x, &y);
6574 	    }
6575 	  goto eval;
6576       }
6577     return 0;
6578   eval:
6579     dist =
6580 	sqrt (((x - point_x) * (x - point_x)) +
6581 	      ((y - point_y) * (y - point_y)));
6582     dist_flip =
6583 	sqrt (((x - point_y) * (x - point_y)) +
6584 	      ((y - point_x) * (y - point_x)));
6585     if (dist_flip < dist)
6586 	return 1;
6587     return 0;
6588 }
6589 
6590 static void
getProjParams(void * p_sqlite,int srid,char ** proj_params)6591 getProjParams (void *p_sqlite, int srid, char **proj_params)
6592 {
6593 /* retrieves the PROJ params from SPATIAL_SYS_REF table, if possible */
6594     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
6595     char *sql;
6596     char **results;
6597     int rows;
6598     int columns;
6599     int i;
6600     int ret;
6601     int len;
6602     const char *proj4text;
6603     char *errMsg = NULL;
6604     *proj_params = NULL;
6605     sql = sqlite3_mprintf
6606 	("SELECT proj4text FROM spatial_ref_sys WHERE srid = %d", srid);
6607     ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &errMsg);
6608     sqlite3_free (sql);
6609     if (ret != SQLITE_OK)
6610       {
6611 	  fprintf (stderr, "unknown SRID: %d\t<%s>\n", srid, errMsg);
6612 	  sqlite3_free (errMsg);
6613 	  return;
6614       }
6615     for (i = 1; i <= rows; i++)
6616       {
6617 	  proj4text = results[(i * columns)];
6618 	  if (proj4text != NULL)
6619 	    {
6620 		len = strlen (proj4text);
6621 		*proj_params = malloc (len + 1);
6622 		strcpy (*proj_params, proj4text);
6623 	    }
6624       }
6625     if (*proj_params == NULL)
6626 	fprintf (stderr, "unknown SRID: %d\n", srid);
6627     sqlite3_free_table (results);
6628 }
6629 
6630 static gaiaGeomCollPtr
reproject(gaiaGeomCollPtr geom,int srid,sqlite3 * sqlite)6631 reproject (gaiaGeomCollPtr geom, int srid, sqlite3 * sqlite)
6632 {
6633 /* attempting to reproject into a different CRS */
6634     char *proj_from;
6635     char *proj_to;
6636     gaiaGeomCollPtr g2 = NULL;
6637     getProjParams (sqlite, geom->Srid, &proj_from);
6638     getProjParams (sqlite, srid, &proj_to);
6639     if (proj_to == NULL || proj_from == NULL)
6640 	;
6641     else
6642 	g2 = gaiaTransform (geom, proj_from, proj_to);
6643     if (proj_from)
6644 	free (proj_from);
6645     if (proj_to)
6646 	free (proj_to);
6647     return g2;
6648 }
6649 
6650 RL2_DECLARE void
wms_feature_collection_parse_geometries(rl2WmsFeatureCollectionPtr handle,int srid,double point_x,double point_y,sqlite3 * sqlite)6651 wms_feature_collection_parse_geometries (rl2WmsFeatureCollectionPtr
6652 					 handle, int srid, double point_x,
6653 					 double point_y, sqlite3 * sqlite)
6654 {
6655 /* attempting to parse any GML Geometry contained within a Feature Collection object */
6656     wmsFeatureMemberPtr member;
6657     wmsFeatureCollectionPtr ptr = (wmsFeatureCollectionPtr) handle;
6658     if (ptr == NULL)
6659 	return;
6660 
6661     member = ptr->first;
6662     while (member != NULL)
6663       {
6664 	  /* looping on FeatureMembers */
6665 	  wmsFeatureAttributePtr attr;
6666 	  attr = member->first;
6667 	  while (attr != NULL)
6668 	    {
6669 		/* looping on FeatureAttributes */
6670 		if (attr->value != NULL)
6671 		  {
6672 		      /* attempting to parse a possible GML Geometry */
6673 		      gaiaGeomCollPtr geom =
6674 			  gaiaParseGml ((const unsigned char *) (attr->value),
6675 					sqlite);
6676 		      if (geom != NULL)
6677 			{
6678 			    if (geom->Srid > 0 && srid > 0
6679 				&& geom->Srid != srid)
6680 			      {
6681 				  /* attempting to reproject into the Map CRS */
6682 				  gaiaGeomCollPtr g2 =
6683 				      reproject (geom, srid, sqlite);
6684 				  if (g2 != NULL)
6685 				    {
6686 					if (check_swap (g2, point_x, point_y))
6687 					  {
6688 					      gaiaFreeGeomColl (g2);
6689 					      gaiaSwapCoords (geom);
6690 					      g2 = reproject (geom, srid,
6691 							      sqlite);
6692 					      attr->geometry = g2;
6693 					      gaiaFreeGeomColl (geom);
6694 					  }
6695 					else
6696 					  {
6697 					      attr->geometry = g2;
6698 					      gaiaFreeGeomColl (geom);
6699 					  }
6700 				    }
6701 			      }
6702 			    else
6703 			      {
6704 				  if (check_swap (geom, point_x, point_y))
6705 				      gaiaSwapCoords (geom);
6706 				  attr->geometry = geom;
6707 			      }
6708 			}
6709 		  }
6710 		attr = attr->next;
6711 	    }
6712 	  member = member->next;
6713       }
6714 }
6715 
6716 RL2_DECLARE int
get_wms_feature_members_count(rl2WmsFeatureCollectionPtr handle)6717 get_wms_feature_members_count (rl2WmsFeatureCollectionPtr handle)
6718 {
6719 /* counting how many Feature Members are contained within a WMS-FeatureCollection */
6720     int count = 0;
6721     wmsFeatureMemberPtr member;
6722     wmsFeatureCollectionPtr ptr = (wmsFeatureCollectionPtr) handle;
6723     if (ptr == NULL)
6724 	return -1;
6725 
6726     member = ptr->first;
6727     while (member != NULL)
6728       {
6729 	  count++;
6730 	  member = member->next;
6731       }
6732     return count;
6733 }
6734 
6735 RL2_DECLARE rl2WmsFeatureMemberPtr
get_wms_feature_member(rl2WmsFeatureCollectionPtr handle,int index)6736 get_wms_feature_member (rl2WmsFeatureCollectionPtr handle, int index)
6737 {
6738 /* attempting to get the Nth FeatureMember from some WMS-FeatureCollection object */
6739     int count = 0;
6740     wmsFeatureMemberPtr member;
6741     wmsFeatureCollectionPtr ptr = (wmsFeatureCollectionPtr) handle;
6742     if (ptr == NULL)
6743 	return NULL;
6744 
6745     member = ptr->first;
6746     while (member != NULL)
6747       {
6748 	  if (count == index)
6749 	      return (rl2WmsFeatureMemberPtr) member;
6750 	  count++;
6751 	  member = member->next;
6752       }
6753     return NULL;
6754 }
6755 
6756 RL2_DECLARE int
get_wms_feature_attributes_count(rl2WmsFeatureMemberPtr handle)6757 get_wms_feature_attributes_count (rl2WmsFeatureMemberPtr handle)
6758 {
6759 /* counting how many Feature Attributes are contained within a WMS-FeatureMember */
6760     int count = 0;
6761     wmsFeatureAttributePtr attr;
6762     wmsFeatureMemberPtr ptr = (wmsFeatureMemberPtr) handle;
6763     if (ptr == NULL)
6764 	return -1;
6765 
6766     attr = ptr->first;
6767     while (attr != NULL)
6768       {
6769 	  count++;
6770 	  attr = attr->next;
6771       }
6772     return count;
6773 }
6774 
6775 RL2_DECLARE const char *
get_wms_feature_attribute_name(rl2WmsFeatureMemberPtr handle,int index)6776 get_wms_feature_attribute_name (rl2WmsFeatureMemberPtr handle, int index)
6777 {
6778 /* attempting to get the Nth FeatureAttribute (Name) from some WMS-FeatureMember object */
6779     int count = 0;
6780     wmsFeatureAttributePtr attr;
6781     wmsFeatureMemberPtr ptr = (wmsFeatureMemberPtr) handle;
6782     if (ptr == NULL)
6783 	return NULL;
6784 
6785     attr = ptr->first;
6786     while (attr != NULL)
6787       {
6788 	  if (count == index)
6789 	      return attr->name;
6790 	  count++;
6791 	  attr = attr->next;
6792       }
6793     return NULL;
6794 }
6795 
6796 RL2_DECLARE gaiaGeomCollPtr
get_wms_feature_attribute_geometry(rl2WmsFeatureMemberPtr handle,int index)6797 get_wms_feature_attribute_geometry (rl2WmsFeatureMemberPtr handle, int index)
6798 {
6799 /* attempting to get the Nth FeatureAttribute (Geometry) from some WMS-FeatureMember object */
6800     int count = 0;
6801     wmsFeatureAttributePtr attr;
6802     wmsFeatureMemberPtr ptr = (wmsFeatureMemberPtr) handle;
6803     if (ptr == NULL)
6804 	return NULL;
6805 
6806     attr = ptr->first;
6807     while (attr != NULL)
6808       {
6809 	  if (count == index)
6810 	      return attr->geometry;
6811 	  count++;
6812 	  attr = attr->next;
6813       }
6814     return NULL;
6815 }
6816 
6817 RL2_DECLARE const char *
get_wms_feature_attribute_value(rl2WmsFeatureMemberPtr handle,int index)6818 get_wms_feature_attribute_value (rl2WmsFeatureMemberPtr handle, int index)
6819 {
6820 /* attempting to get the Nth FeatureAttribute (Value) from some WMS-FeatureMember object */
6821     int count = 0;
6822     wmsFeatureAttributePtr attr;
6823     wmsFeatureMemberPtr ptr = (wmsFeatureMemberPtr) handle;
6824     if (ptr == NULL)
6825 	return NULL;
6826 
6827     attr = ptr->first;
6828     while (attr != NULL)
6829       {
6830 	  if (count == index)
6831 	      return attr->value;
6832 	  count++;
6833 	  attr = attr->next;
6834       }
6835     return NULL;
6836 }
6837 
6838 static int
check_marker(const char * url)6839 check_marker (const char *url)
6840 {
6841 /* testing if some "?" marker is already defined */
6842     int i;
6843     int force_marker = 1;
6844     for (i = 0; i < (int) strlen (url); i++)
6845       {
6846 	  if (*(url + i) == '?')
6847 	      force_marker = 0;
6848       }
6849     return force_marker;
6850 }
6851 
6852 RL2_DECLARE unsigned char *
do_wms_GetMap_get(rl2WmsCachePtr cache_handle,const char * url,const char * proxy,const char * version,const char * layer,const char * crs,int swap_xy,double minx,double miny,double maxx,double maxy,int width,int height,const char * style,const char * format,int opaque,int from_cache,char ** err_msg)6853 do_wms_GetMap_get (rl2WmsCachePtr cache_handle, const char *url,
6854 		   const char *proxy, const char *version, const char *layer,
6855 		   const char *crs, int swap_xy, double minx, double miny,
6856 		   double maxx, double maxy, int width, int height,
6857 		   const char *style, const char *format, int opaque,
6858 		   int from_cache, char **err_msg)
6859 {
6860 /* attempting to execute a WMS GepMap request [method GET] */
6861     CURL *curl = NULL;
6862     CURLcode res;
6863     wmsMemBuffer headerBuf;
6864     wmsMemBuffer bodyBuf;
6865     int http_status;
6866     char *http_code;
6867     char *request;
6868     char *image_format;
6869     unsigned char *rgba = NULL;
6870     int force_marker = check_marker (url);
6871     const char *crs_prefix = "CRS";
6872     rl2RasterPtr raster = NULL;
6873     wmsCachePtr cache = (wmsCachePtr) cache_handle;
6874 
6875     *err_msg = NULL;
6876     if (from_cache && cache == NULL)
6877 	return NULL;
6878 
6879 /* masking NULL arguments */
6880     if (url == NULL)
6881 	url = "";
6882     if (version == NULL)
6883 	version = "";
6884     if (layer == NULL)
6885 	layer = "";
6886     if (crs == NULL)
6887 	crs = "";
6888     if (style == NULL)
6889 	style = "";
6890     if (format == NULL)
6891 	format = "";
6892 
6893 /* preparing the request URL */
6894     if (strcmp (version, "1.3.0") < 0)
6895       {
6896 	  /* earlier versions of the protocol require SRS instead of CRS */
6897 	  crs_prefix = "SRS";
6898       }
6899     if (force_marker)
6900       {
6901 	  /* "?" marker not declared */
6902 	  if (swap_xy)
6903 	      request =
6904 		  sqlite3_mprintf ("%s?SERVICE=WMS&REQUEST=GetMap&VERSION=%s"
6905 				   "&LAYERS=%s&%s=%s&BBOX=%1.6f,%1.6f,%1.6f,%1.6f"
6906 				   "&WIDTH=%d&HEIGHT=%d&STYLES=%s&FORMAT=%s"
6907 				   "&TRANSPARENT=%s&BGCOLOR=0xFFFFFF", url,
6908 				   version, layer, crs_prefix, crs, miny, minx,
6909 				   maxy, maxx, width, height, style, format,
6910 				   (opaque == 0) ? "TRUE" : "FALSE");
6911 	  else
6912 	      request =
6913 		  sqlite3_mprintf ("%s?SERVICE=WMS&REQUEST=GetMap&VERSION=%s"
6914 				   "&LAYERS=%s&%s=%s&BBOX=%1.6f,%1.6f,%1.6f,%1.6f"
6915 				   "&WIDTH=%d&HEIGHT=%d&STYLES=%s&FORMAT=%s"
6916 				   "&TRANSPARENT=%s&BGCOLOR=0xFFFFFF", url,
6917 				   version, layer, crs_prefix, crs, minx, miny,
6918 				   maxx, maxy, width, height, style, format,
6919 				   (opaque == 0) ? "TRUE" : "FALSE");
6920       }
6921     else
6922       {
6923 	  /* "?" marker already defined */
6924 	  if (swap_xy)
6925 	      request =
6926 		  sqlite3_mprintf ("%sSERVICE=WMS&REQUEST=GetMap&VERSION=%s"
6927 				   "&LAYERS=%s&%s=%s&BBOX=%1.6f,%1.6f,%1.6f,%1.6f"
6928 				   "&WIDTH=%d&HEIGHT=%d&STYLES=%s&FORMAT=%s"
6929 				   "&TRANSPARENT=%s&BGCOLOR=0xFFFFFF", url,
6930 				   version, layer, crs_prefix, crs, miny, minx,
6931 				   maxy, maxx, width, height, style, format,
6932 				   (opaque == 0) ? "TRUE" : "FALSE");
6933 	  else
6934 	      request =
6935 		  sqlite3_mprintf ("%sSERVICE=WMS&REQUEST=GetMap&VERSION=%s"
6936 				   "&LAYERS=%s&%s=%s&BBOX=%1.6f,%1.6f,%1.6f,%1.6f"
6937 				   "&WIDTH=%d&HEIGHT=%d&STYLES=%s&FORMAT=%s"
6938 				   "&TRANSPARENT=%s&BGCOLOR=0xFFFFFF", url,
6939 				   version, layer, crs_prefix, crs, minx, miny,
6940 				   maxx, maxy, width, height, style, format,
6941 				   (opaque == 0) ? "TRUE" : "FALSE");
6942       }
6943 
6944     if (cache != NULL)
6945       {
6946 	  /* checks if it's already stored into the WMS Cache */
6947 	  wmsCachedItemPtr cachedItem = getWmsCachedItem (cache, request);
6948 	  if (cachedItem != NULL)
6949 	    {
6950 		/* ok, found from WMS Cache */
6951 		time_t xtime;
6952 		time (&xtime);
6953 		cachedItem->Time = xtime;
6954 		/* attempting to decode an RGBA image */
6955 		if (cachedItem->ImageFormat == WMS_FORMAT_GIF)
6956 		    raster =
6957 			rl2_raster_from_gif (cachedItem->Item,
6958 					     cachedItem->Size);
6959 		if (cachedItem->ImageFormat == WMS_FORMAT_PNG)
6960 		    raster =
6961 			rl2_raster_from_png (cachedItem->Item,
6962 					     cachedItem->Size);
6963 		if (cachedItem->ImageFormat == WMS_FORMAT_JPEG)
6964 		    raster =
6965 			rl2_raster_from_jpeg (cachedItem->Item,
6966 					      cachedItem->Size);
6967 		if (cachedItem->ImageFormat == WMS_FORMAT_TIFF)
6968 		    raster =
6969 			rl2_raster_from_tiff (cachedItem->Item,
6970 					      cachedItem->Size);
6971 		goto image_ready;
6972 	    }
6973       }
6974     if (from_cache)
6975       {
6976 	  sqlite3_free (request);
6977 	  return NULL;
6978       }
6979 
6980     curl = curl_easy_init ();
6981     if (curl)
6982       {
6983 	  /* setting the URL */
6984 	  curl_easy_setopt (curl, CURLOPT_URL, request);
6985 
6986 	  if (proxy != NULL)
6987 	    {
6988 		/* setting up the required proxy */
6989 		curl_easy_setopt (curl, CURLOPT_PROXY, proxy);
6990 	    }
6991 
6992 	  /* no progress meter please */
6993 	  curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1L);
6994 	  /* setting the output callback function */
6995 	  curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, store_data);
6996 
6997 	  /* initializes the dynamically growing buffers */
6998 	  wmsMemBufferInitialize (&headerBuf);
6999 	  wmsMemBufferInitialize (&bodyBuf);
7000 	  curl_easy_setopt (curl, CURLOPT_WRITEHEADER, &headerBuf);
7001 	  curl_easy_setopt (curl, CURLOPT_WRITEDATA, &bodyBuf);
7002 
7003 	  /* Perform the request, res will get the return code */
7004 	  res = curl_easy_perform (curl);
7005 	  /* Check for errors */
7006 	  if (res != CURLE_OK)
7007 	    {
7008 		fprintf (stderr, "CURL error: %s\n", curl_easy_strerror (res));
7009 		goto stop;
7010 	    }
7011 
7012 	  /* verifying the HTTP status code */
7013 	  check_http_header (&headerBuf, &http_status, &http_code);
7014 	  if (http_status == 302)
7015 	    {
7016 		while (1)
7017 		  {
7018 		      /* following a redirect */
7019 		      char *redir = parse_http_redirect (&headerBuf);
7020 		      if (redir == NULL)
7021 			  break;
7022 		      /* resetting all buffers */
7023 		      if (http_code != NULL)
7024 			  free (http_code);
7025 		      wmsMemBufferReset (&headerBuf);
7026 		      wmsMemBufferReset (&bodyBuf);
7027 		      curl_easy_setopt (curl, CURLOPT_URL, redir);
7028 		      if (proxy != NULL)
7029 			  curl_easy_setopt (curl, CURLOPT_PROXY, proxy);
7030 		      res = curl_easy_perform (curl);
7031 		      if (res != CURLE_OK)
7032 			{
7033 			    fprintf (stderr, "CURL error: %s\n",
7034 				     curl_easy_strerror (res));
7035 			    goto stop;
7036 			}
7037 		      free (redir);
7038 		      check_http_header (&headerBuf, &http_status, &http_code);
7039 		      if (http_status == 302)
7040 			  continue;
7041 		      break;
7042 		  }
7043 
7044 	    }
7045 	  if (http_status != 200)
7046 	    {
7047 		fprintf (stderr, "Invalid HTTP status code: %d %s\n",
7048 			 http_status, http_code);
7049 		if (http_code != NULL)
7050 		    free (http_code);
7051 		goto stop;
7052 	    }
7053 	  if (http_code != NULL)
7054 	      free (http_code);
7055 
7056 	  /* attempting to decode an RGBA image */
7057 	  image_format = parse_http_format (&headerBuf);
7058 	  if (strcmp (image_format, "image/gif") == 0)
7059 	      raster =
7060 		  rl2_raster_from_gif (bodyBuf.Buffer, bodyBuf.WriteOffset);
7061 	  if (strcmp (image_format, "image/png") == 0)
7062 	      raster =
7063 		  rl2_raster_from_png (bodyBuf.Buffer, bodyBuf.WriteOffset);
7064 	  if (strcmp (image_format, "image/jpeg") == 0)
7065 	      raster =
7066 		  rl2_raster_from_jpeg (bodyBuf.Buffer, bodyBuf.WriteOffset);
7067 	  if (strcmp (image_format, "image/tiff") == 0)
7068 	      raster =
7069 		  rl2_raster_from_tiff (bodyBuf.Buffer, bodyBuf.WriteOffset);
7070 
7071 	  if (raster != NULL)
7072 	    {
7073 		/* saving into the WMS Cache */
7074 		wmsAddCachedItem (cache, request, bodyBuf.Buffer,
7075 				  bodyBuf.WriteOffset, image_format);
7076 	    }
7077 
7078 	  if (image_format != NULL)
7079 	      free (image_format);
7080 
7081 	stop:
7082 	  wmsMemBufferReset (&headerBuf);
7083 	  wmsMemBufferReset (&bodyBuf);
7084 	  curl_easy_cleanup (curl);
7085       }
7086 
7087   image_ready:
7088     sqlite3_free (request);
7089 
7090     if (raster != NULL)
7091       {
7092 	  /* exporting the image into an RGBA pix-buffer */
7093 	  int size;
7094 	  int ret = rl2_raster_data_to_RGBA (raster, &rgba, &size);
7095 	  rl2_destroy_raster (raster);
7096 	  if (ret == RL2_OK && rgba != NULL && size == (width * height * 4))
7097 	      return rgba;
7098 	  if (rgba != NULL)
7099 	      free (rgba);
7100 	  rgba = NULL;
7101       }
7102     return rgba;
7103 }
7104 
7105 RL2_DECLARE unsigned char *
do_wms_GetMap_post(rl2WmsCachePtr cache_handle,const char * url,const char * proxy,const char * version,const char * layer,const char * crs,int swap_xy,double minx,double miny,double maxx,double maxy,int width,int height,const char * style,const char * format,int opaque,int from_cache,char ** err_msg)7106 do_wms_GetMap_post (rl2WmsCachePtr cache_handle, const char *url,
7107 		    const char *proxy, const char *version, const char *layer,
7108 		    const char *crs, int swap_xy, double minx, double miny,
7109 		    double maxx, double maxy, int width, int height,
7110 		    const char *style, const char *format, int opaque,
7111 		    int from_cache, char **err_msg)
7112 {
7113 /* attempting to execute a WMS GepMap request [method POST] */
7114 
7115 /* not yet implemented: just a stupid placeholder always returning NULL */
7116     if (cache_handle == NULL || url == NULL || proxy == NULL || version == NULL
7117 	|| layer == NULL || crs == NULL)
7118 	return NULL;
7119     if (minx == miny || maxx == maxy || width == height || opaque == from_cache
7120 	|| width == swap_xy)
7121 	return NULL;
7122     if (style == NULL || format == NULL || err_msg == NULL)
7123 	return NULL;
7124     return NULL;
7125 }
7126 
7127 RL2_DECLARE unsigned char *
do_wms_GetMap_TileService_get(rl2WmsCachePtr cache_handle,const char * url,const char * proxy,int width,int height,int from_cache,char ** err_msg)7128 do_wms_GetMap_TileService_get (rl2WmsCachePtr cache_handle, const char *url,
7129 			       const char *proxy, int width, int height,
7130 			       int from_cache, char **err_msg)
7131 {
7132 /* attempting to execute a WMS GepMap TileService request [method GET] */
7133     CURL *curl = NULL;
7134     CURLcode res;
7135     wmsMemBuffer headerBuf;
7136     wmsMemBuffer bodyBuf;
7137     int http_status;
7138     char *http_code;
7139     char *image_format;
7140     unsigned char *rgba = NULL;
7141     rl2RasterPtr raster = NULL;
7142     wmsCachePtr cache = (wmsCachePtr) cache_handle;
7143 
7144     *err_msg = NULL;
7145     if (from_cache && cache == NULL)
7146 	return NULL;
7147 
7148 /* masking NULL arguments */
7149     if (url == NULL)
7150 	url = "";
7151 
7152     if (cache != NULL)
7153       {
7154 	  /* checks if it's already stored into the WMS Cache */
7155 	  wmsCachedItemPtr cachedItem = getWmsCachedItem (cache, url);
7156 	  if (cachedItem != NULL)
7157 	    {
7158 		/* ok, found from WMS Cache */
7159 		time_t xtime;
7160 		time (&xtime);
7161 		cachedItem->Time = xtime;
7162 		/* attempting to decode an RGBA image */
7163 		if (cachedItem->ImageFormat == WMS_FORMAT_GIF)
7164 		    raster =
7165 			rl2_raster_from_gif (cachedItem->Item,
7166 					     cachedItem->Size);
7167 		if (cachedItem->ImageFormat == WMS_FORMAT_PNG)
7168 		    raster =
7169 			rl2_raster_from_png (cachedItem->Item,
7170 					     cachedItem->Size);
7171 		if (cachedItem->ImageFormat == WMS_FORMAT_JPEG)
7172 		    raster =
7173 			rl2_raster_from_jpeg (cachedItem->Item,
7174 					      cachedItem->Size);
7175 		if (cachedItem->ImageFormat == WMS_FORMAT_TIFF)
7176 		    raster =
7177 			rl2_raster_from_tiff (cachedItem->Item,
7178 					      cachedItem->Size);
7179 		goto image_ready;
7180 	    }
7181       }
7182     if (from_cache)
7183 	return NULL;
7184 
7185     curl = curl_easy_init ();
7186     if (curl)
7187       {
7188 	  /* setting the URL */
7189 	  curl_easy_setopt (curl, CURLOPT_URL, url);
7190 
7191 	  if (proxy != NULL)
7192 	    {
7193 		/* setting up the required proxy */
7194 		curl_easy_setopt (curl, CURLOPT_PROXY, proxy);
7195 	    }
7196 
7197 	  /* no progress meter please */
7198 	  curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1L);
7199 	  /* setting the output callback function */
7200 	  curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, store_data);
7201 
7202 	  /* initializes the dynamically growing buffers */
7203 	  wmsMemBufferInitialize (&headerBuf);
7204 	  wmsMemBufferInitialize (&bodyBuf);
7205 	  curl_easy_setopt (curl, CURLOPT_WRITEHEADER, &headerBuf);
7206 	  curl_easy_setopt (curl, CURLOPT_WRITEDATA, &bodyBuf);
7207 
7208 	  /* Perform the request, res will get the return code */
7209 	  res = curl_easy_perform (curl);
7210 	  /* Check for errors */
7211 	  if (res != CURLE_OK)
7212 	    {
7213 		fprintf (stderr, "CURL error: %s\n", curl_easy_strerror (res));
7214 		goto stop;
7215 	    }
7216 
7217 	  /* verifying the HTTP status code */
7218 	  check_http_header (&headerBuf, &http_status, &http_code);
7219 	  if (http_status == 302)
7220 	    {
7221 		while (1)
7222 		  {
7223 		      /* following a redirect */
7224 		      char *redir = parse_http_redirect (&headerBuf);
7225 		      if (redir == NULL)
7226 			  break;
7227 		      /* resetting all buffers */
7228 		      if (http_code != NULL)
7229 			  free (http_code);
7230 		      wmsMemBufferReset (&headerBuf);
7231 		      wmsMemBufferReset (&bodyBuf);
7232 		      curl_easy_setopt (curl, CURLOPT_URL, redir);
7233 		      if (proxy != NULL)
7234 			  curl_easy_setopt (curl, CURLOPT_PROXY, proxy);
7235 		      res = curl_easy_perform (curl);
7236 		      if (res != CURLE_OK)
7237 			{
7238 			    fprintf (stderr, "CURL error: %s\n",
7239 				     curl_easy_strerror (res));
7240 			    goto stop;
7241 			}
7242 		      free (redir);
7243 		      check_http_header (&headerBuf, &http_status, &http_code);
7244 		      if (http_status == 302)
7245 			  continue;
7246 		      break;
7247 		  }
7248 
7249 	    }
7250 	  if (http_status != 200)
7251 	    {
7252 		fprintf (stderr, "Invalid HTTP status code: %d %s\n",
7253 			 http_status, http_code);
7254 		if (http_code != NULL)
7255 		    free (http_code);
7256 		goto stop;
7257 	    }
7258 	  if (http_code != NULL)
7259 	      free (http_code);
7260 
7261 	  /* attempting to decode an RGBA image */
7262 	  image_format = parse_http_format (&headerBuf);
7263 	  if (strcmp (image_format, "image/gif") == 0)
7264 	      raster =
7265 		  rl2_raster_from_gif (bodyBuf.Buffer, bodyBuf.WriteOffset);
7266 	  if (strcmp (image_format, "image/png") == 0)
7267 	      raster =
7268 		  rl2_raster_from_png (bodyBuf.Buffer, bodyBuf.WriteOffset);
7269 	  if (strcmp (image_format, "image/jpeg") == 0)
7270 	      raster =
7271 		  rl2_raster_from_jpeg (bodyBuf.Buffer, bodyBuf.WriteOffset);
7272 	  if (strcmp (image_format, "image/tiff") == 0)
7273 	      raster =
7274 		  rl2_raster_from_tiff (bodyBuf.Buffer, bodyBuf.WriteOffset);
7275 
7276 	  if (raster != NULL)
7277 	    {
7278 		/* saving into the WMS Cache */
7279 		wmsAddCachedItem (cache, url, bodyBuf.Buffer,
7280 				  bodyBuf.WriteOffset, image_format);
7281 	    }
7282 
7283 	  if (image_format != NULL)
7284 	      free (image_format);
7285 
7286 	stop:
7287 	  wmsMemBufferReset (&headerBuf);
7288 	  wmsMemBufferReset (&bodyBuf);
7289 	  curl_easy_cleanup (curl);
7290       }
7291 
7292   image_ready:
7293 
7294     if (raster != NULL)
7295       {
7296 	  /* exporting the image into an RGBA pix-buffer */
7297 	  int size;
7298 	  int ret = rl2_raster_data_to_RGBA (raster, &rgba, &size);
7299 	  rl2_destroy_raster (raster);
7300 	  if (ret == RL2_OK && rgba != NULL && size == (width * height * 4))
7301 	      return rgba;
7302 	  if (rgba != NULL)
7303 	      free (rgba);
7304 	  rgba = NULL;
7305       }
7306     return rgba;
7307 }
7308 
7309 RL2_DECLARE unsigned char *
do_wms_GetMap_TileService_post(rl2WmsCachePtr cache_handle,const char * url,const char * proxy,int width,int height,int from_cache,char ** err_msg)7310 do_wms_GetMap_TileService_post (rl2WmsCachePtr cache_handle, const char *url,
7311 				const char *proxy, int width, int height,
7312 				int from_cache, char **err_msg)
7313 {
7314 /* attempting to execute a WMS GepMap TileService request [method POST] */
7315 
7316 /* not yet implemented: just a stupid placeholder always returning NULL */
7317     if (cache_handle == NULL || url == NULL || proxy == NULL || err_msg == NULL)
7318 	return NULL;
7319     if (width == height || width == from_cache)
7320 	return NULL;
7321     return NULL;
7322 }
7323 
7324 RL2_DECLARE rl2WmsFeatureCollectionPtr
do_wms_GetFeatureInfo_get(const char * url,const char * proxy,const char * version,const char * format,const char * layer,const char * crs,int swap_xy,double minx,double miny,double maxx,double maxy,int width,int height,int mouse_x,int mouse_y,char ** err_msg)7325 do_wms_GetFeatureInfo_get (const char *url, const char *proxy,
7326 			   const char *version, const char *format,
7327 			   const char *layer, const char *crs, int swap_xy,
7328 			   double minx, double miny, double maxx, double maxy,
7329 			   int width, int height, int mouse_x, int mouse_y,
7330 			   char **err_msg)
7331 {
7332 /* attempting to execute a WMS GepFeatureInfo request [method GET] */
7333     CURL *curl = NULL;
7334     CURLcode res;
7335     wmsMemBuffer headerBuf;
7336     wmsMemBuffer bodyBuf;
7337     wmsFeatureCollectionPtr coll = NULL;
7338     int http_status;
7339     char *http_code;
7340     char *request;
7341     char *multipart_boundary;
7342     const char *crs_prefix = "CRS";
7343     char *xml_buf;
7344     int force_marker = check_marker (url);
7345 
7346     *err_msg = NULL;
7347 
7348 /* masking NULL arguments */
7349     if (url == NULL)
7350 	url = "";
7351     if (version == NULL)
7352 	version = "";
7353     if (format == NULL)
7354 	format = "";
7355     if (layer == NULL)
7356 	layer = "";
7357     if (crs == NULL)
7358 	crs = "";
7359 
7360 /* preparing the request URL */
7361     if (strcmp (version, "1.3.0") < 0)
7362       {
7363 	  /* earlier versions of the protocol require SRS instead of CRS */
7364 	  crs_prefix = "SRS";
7365       }
7366     if (force_marker)
7367       {
7368 	  if (swap_xy)
7369 	      request =
7370 		  sqlite3_mprintf
7371 		  ("%s?SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=%s&LAYERS=%s"
7372 		   "&QUERY_LAYERS=%s&%s=%s&BBOX=%1.6f,%1.6f,%1.6f,%1.6f"
7373 		   "&WIDTH=%d&HEIGHT=%d&X=%d&Y=%d&INFO_FORMAT=%s"
7374 		   "&FEATURE_COUNT=50", url, version, layer, layer, crs_prefix,
7375 		   crs, miny, minx, maxy, maxx, width, height, mouse_x,
7376 		   mouse_y, format);
7377 	  else
7378 	      request =
7379 		  sqlite3_mprintf
7380 		  ("%s?SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=%s&LAYERS=%s"
7381 		   "&QUERY_LAYERS=%s&%s=%s&BBOX=%1.6f,%1.6f,%1.6f,%1.6f"
7382 		   "&WIDTH=%d&HEIGHT=%d&X=%d&Y=%d&INFO_FORMAT=%s"
7383 		   "&FEATURE_COUNT=50", url, version, layer, layer, crs_prefix,
7384 		   crs, minx, miny, maxx, maxy, width, height, mouse_x,
7385 		   mouse_y, format);
7386       }
7387     else
7388       {
7389 	  if (swap_xy)
7390 	      request =
7391 		  sqlite3_mprintf
7392 		  ("%sSERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=%s&LAYERS=%s"
7393 		   "&QUERY_LAYERS=%s&%s=%s&BBOX=%1.6f,%1.6f,%1.6f,%1.6f"
7394 		   "&WIDTH=%d&HEIGHT=%d&X=%d&Y=%d&INFO_FORMAT=%s"
7395 		   "&FEATURE_COUNT=50", url, version, layer, layer, crs_prefix,
7396 		   crs, miny, minx, maxy, maxx, width, height, mouse_x,
7397 		   mouse_y, format);
7398 	  else
7399 	      request =
7400 		  sqlite3_mprintf
7401 		  ("%sSERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=%s&LAYERS=%s"
7402 		   "&QUERY_LAYERS=%s&%s=%s&BBOX=%1.6f,%1.6f,%1.6f,%1.6f"
7403 		   "&WIDTH=%d&HEIGHT=%d&X=%d&Y=%d&INFO_FORMAT=%s"
7404 		   "&FEATURE_COUNT=50", url, version, layer, layer, crs_prefix,
7405 		   crs, minx, miny, maxx, maxy, width, height, mouse_x,
7406 		   mouse_y, format);
7407       }
7408 
7409     curl = curl_easy_init ();
7410     if (curl)
7411       {
7412 	  /* setting the URL */
7413 	  curl_easy_setopt (curl, CURLOPT_URL, request);
7414 
7415 	  if (proxy != NULL)
7416 	    {
7417 		/* setting up the required proxy */
7418 		curl_easy_setopt (curl, CURLOPT_PROXY, proxy);
7419 	    }
7420 
7421 	  /* no progress meter please */
7422 	  curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 1L);
7423 	  /* setting the output callback function */
7424 	  curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, store_data);
7425 
7426 	  /* initializes the dynamically growing buffers */
7427 	  wmsMemBufferInitialize (&headerBuf);
7428 	  wmsMemBufferInitialize (&bodyBuf);
7429 	  curl_easy_setopt (curl, CURLOPT_WRITEHEADER, &headerBuf);
7430 	  curl_easy_setopt (curl, CURLOPT_WRITEDATA, &bodyBuf);
7431 
7432 	  /* Perform the request, res will get the return code */
7433 	  res = curl_easy_perform (curl);
7434 	  /* Check for errors */
7435 	  if (res != CURLE_OK)
7436 	    {
7437 		fprintf (stderr, "CURL error: %s\n", curl_easy_strerror (res));
7438 		goto stop;
7439 	    }
7440 
7441 	  /* verifying the HTTP status code */
7442 	  check_http_header (&headerBuf, &http_status, &http_code);
7443 	  if (http_status == 302)
7444 	    {
7445 		while (1)
7446 		  {
7447 		      /* following a redirect */
7448 		      char *redir = parse_http_redirect (&headerBuf);
7449 		      if (redir == NULL)
7450 			  break;
7451 		      /* resetting all buffers */
7452 		      if (http_code != NULL)
7453 			  free (http_code);
7454 		      wmsMemBufferReset (&headerBuf);
7455 		      wmsMemBufferReset (&bodyBuf);
7456 		      curl_easy_setopt (curl, CURLOPT_URL, redir);
7457 		      if (proxy != NULL)
7458 			  curl_easy_setopt (curl, CURLOPT_PROXY, proxy);
7459 		      res = curl_easy_perform (curl);
7460 		      if (res != CURLE_OK)
7461 			{
7462 			    fprintf (stderr, "CURL error: %s\n",
7463 				     curl_easy_strerror (res));
7464 			    goto stop;
7465 			}
7466 		      free (redir);
7467 		      check_http_header (&headerBuf, &http_status, &http_code);
7468 		      if (http_status == 302)
7469 			  continue;
7470 		      break;
7471 		  }
7472 
7473 	    }
7474 	  if (http_status != 200)
7475 	    {
7476 		fprintf (stderr, "Invalid HTTP status code: %d %s\n",
7477 			 http_status, http_code);
7478 		if (http_code != NULL)
7479 		    free (http_code);
7480 		goto stop;
7481 	    }
7482 	  if (http_code != NULL)
7483 	      free (http_code);
7484 
7485 	  multipart_boundary = check_http_multipart_response (&headerBuf);
7486 	  if (multipart_boundary != NULL)
7487 	    {
7488 		wmsMultipartCollectionPtr multi =
7489 		    parse_multipart_body (&bodyBuf, multipart_boundary);
7490 		free (multipart_boundary);
7491 		if (multi != NULL)
7492 		  {
7493 		      wmsSinglePartResponsePtr single = multi->first;
7494 		      while (single != NULL)
7495 			{
7496 			    xml_buf = clean_xml_str (single->body);
7497 			    if (xml_buf != NULL)
7498 			      {
7499 				  coll = parse_wms_feature_collection (xml_buf);
7500 				  free (xml_buf);
7501 			      }
7502 			    if (coll != NULL)
7503 			      {
7504 				  wmsFreeMultipartCollection (multi);
7505 				  goto stop;
7506 			      }
7507 			    single = single->next;
7508 			}
7509 		      wmsFreeMultipartCollection (multi);
7510 		  }
7511 	    }
7512 	  else
7513 	    {
7514 		xml_buf = clean_xml (&bodyBuf);
7515 		if (xml_buf != NULL)
7516 		  {
7517 		      coll = parse_wms_feature_collection (xml_buf);
7518 		      free (xml_buf);
7519 		  }
7520 	    }
7521 
7522 	stop:
7523 	  wmsMemBufferReset (&headerBuf);
7524 	  wmsMemBufferReset (&bodyBuf);
7525 	  curl_easy_cleanup (curl);
7526       }
7527 
7528     sqlite3_free (request);
7529     if (coll != NULL)
7530       {
7531 	  if (coll->first == NULL)
7532 	    {
7533 		wmsFreeFeatureCollection (coll);
7534 		coll = NULL;
7535 	    }
7536       }
7537     return (rl2WmsFeatureCollectionPtr) coll;
7538 }
7539 
7540 RL2_DECLARE rl2WmsFeatureCollectionPtr
do_wms_GetFeatureInfo_post(const char * url,const char * proxy,const char * version,const char * format,const char * layer,const char * crs,int swap_xy,double minx,double miny,double maxx,double maxy,int width,int height,int mouse_x,int mouse_y,char ** err_msg)7541 do_wms_GetFeatureInfo_post (const char *url, const char *proxy,
7542 			    const char *version, const char *format,
7543 			    const char *layer, const char *crs, int swap_xy,
7544 			    double minx, double miny, double maxx, double maxy,
7545 			    int width, int height, int mouse_x, int mouse_y,
7546 			    char **err_msg)
7547 {
7548 /* attempting to execute a WMS GepFeatureInfo request [method POST] */
7549 
7550 /* not yet implemented: just a stupid placeholder always returning NULL */
7551     if (url == NULL || proxy == NULL || version == NULL || format == NULL
7552 	|| layer == NULL || crs == NULL)
7553 	return NULL;
7554     if (minx == miny || maxx == maxy || width == height || mouse_x == mouse_y
7555 	|| swap_xy == mouse_x)
7556 	return NULL;
7557     if (err_msg == NULL)
7558 	return NULL;
7559     return NULL;
7560 }
7561