1 /**********************************************************************
2  * $Id$
3  *
4  * Project:  MapServer
5  * Purpose:  OGC Web Map Context implementation
6  * Author:   Julien-Samuel Lacroix, DM Solutions Group (lacroix@dmsolutions.ca)
7  *
8  **********************************************************************
9  * Copyright (c) 2002-2003, Julien-Samuel Lacroix, DM Solutions Group Inc
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies of this Software or works derived from this Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  ****************************************************************************/
28 
29 #include "mapserver.h"
30 #include "mapows.h"
31 
32 #include "cpl_vsi.h"
33 
34 
35 #if defined(USE_WMS_LYR)
36 
37 /* There is a dependency to GDAL/OGR for the GML driver and MiniXML parser */
38 #include "cpl_minixml.h"
39 
40 #endif
41 
42 /* msGetMapContextFileText()
43 **
44 ** Read a file and return is content
45 **
46 ** Take the filename in argument
47 ** Return value must be freed by caller
48 */
msGetMapContextFileText(char * filename)49 char * msGetMapContextFileText(char *filename)
50 {
51   char *pszBuffer;
52   VSILFILE *stream;
53   int  nLength;
54 
55   /* open file */
56   if(filename != NULL && strlen(filename) > 0) {
57     stream = VSIFOpenL(filename, "rb");
58     if(!stream) {
59       msSetError(MS_IOERR, "(%s)", "msGetMapContextFileText()", filename);
60       return NULL;
61     }
62   } else {
63     msSetError(MS_IOERR, "(%s)", "msGetMapContextFileText()", filename);
64     return NULL;
65   }
66 
67   VSIFSeekL( stream, 0, SEEK_END );
68   nLength = (int) VSIFTellL( stream );
69   VSIFSeekL( stream, 0, SEEK_SET );
70 
71   pszBuffer = (char *) malloc(nLength+1);
72   if( pszBuffer == NULL ) {
73     msSetError(MS_MEMERR, "(%s)", "msGetMapContextFileText()", filename);
74     VSIFCloseL( stream );
75     return NULL;
76   }
77 
78   if(VSIFReadL( pszBuffer, nLength, 1, stream ) == 0) {
79     free( pszBuffer );
80     VSIFCloseL( stream );
81     msSetError(MS_IOERR, "(%s)", "msGetMapContextFileText()", filename);
82     return NULL;
83   }
84   pszBuffer[nLength] = '\0';
85 
86   VSIFCloseL( stream );
87 
88   return pszBuffer;
89 }
90 
91 
92 #if defined(USE_WMS_LYR)
93 
94 /*
95 **msGetMapContextXMLHashValue()
96 **
97 **Get the xml value and put it in the hash table
98 **
99 */
msGetMapContextXMLHashValue(CPLXMLNode * psRoot,const char * pszXMLPath,hashTableObj * metadata,char * pszMetadata)100 int msGetMapContextXMLHashValue( CPLXMLNode *psRoot, const char *pszXMLPath,
101                                  hashTableObj *metadata, char *pszMetadata )
102 {
103   char *pszValue;
104 
105   pszValue = (char*)CPLGetXMLValue( psRoot, pszXMLPath, NULL);
106   if(pszValue != NULL) {
107     if( metadata != NULL ) {
108       msInsertHashTable(metadata, pszMetadata, pszValue );
109     } else {
110       return MS_FAILURE;
111     }
112   } else {
113     return MS_FAILURE;
114   }
115 
116   return MS_SUCCESS;
117 }
118 
119 /*
120 **msGetMapContextXMLHashValue()
121 **
122 **Get the xml value and put it in the hash table
123 **
124 */
msGetMapContextXMLHashValueDecode(CPLXMLNode * psRoot,const char * pszXMLPath,hashTableObj * metadata,char * pszMetadata)125 int msGetMapContextXMLHashValueDecode( CPLXMLNode *psRoot,
126                                        const char *pszXMLPath,
127                                        hashTableObj *metadata,
128                                        char *pszMetadata )
129 {
130   char *pszValue;
131 
132   pszValue = (char*)CPLGetXMLValue( psRoot, pszXMLPath, NULL);
133   if(pszValue != NULL) {
134     if( metadata != NULL ) {
135       msDecodeHTMLEntities(pszValue);
136       msInsertHashTable(metadata, pszMetadata, pszValue );
137     } else {
138       return MS_FAILURE;
139     }
140   } else {
141     return MS_FAILURE;
142   }
143 
144   return MS_SUCCESS;
145 }
146 
147 
148 /*
149 **msGetMapContextXMLStringValue()
150 **
151 **Get the xml value and put it in the string field
152 **
153 */
msGetMapContextXMLStringValue(CPLXMLNode * psRoot,char * pszXMLPath,char ** pszField)154 int msGetMapContextXMLStringValue( CPLXMLNode *psRoot, char *pszXMLPath,
155                                    char **pszField)
156 {
157   char *pszValue;
158 
159   pszValue = (char*)CPLGetXMLValue( psRoot, pszXMLPath, NULL);
160   if(pszValue != NULL) {
161     if( pszField != NULL ) {
162       *pszField = msStrdup(pszValue);
163     } else {
164       return MS_FAILURE;
165     }
166   } else {
167     return MS_FAILURE;
168   }
169 
170   return MS_SUCCESS;
171 }
172 
173 
174 /*
175 **msGetMapContextXMLStringValue()
176 **
177 **Get the xml value and put it in the string field
178 **
179 */
msGetMapContextXMLStringValueDecode(CPLXMLNode * psRoot,char * pszXMLPath,char ** pszField)180 int msGetMapContextXMLStringValueDecode( CPLXMLNode *psRoot, char *pszXMLPath,
181     char **pszField)
182 {
183   char *pszValue;
184 
185   pszValue = (char*)CPLGetXMLValue( psRoot, pszXMLPath, NULL);
186   if(pszValue != NULL) {
187     if( pszField != NULL ) {
188       msDecodeHTMLEntities(pszValue);
189       *pszField = msStrdup(pszValue);
190     } else {
191       return MS_FAILURE;
192     }
193   } else {
194     return MS_FAILURE;
195   }
196 
197   return MS_SUCCESS;
198 }
199 
200 
201 /*
202 **msGetMapContextXMLFloatValue()
203 **
204 **Get the xml value and put it in the string field
205 **
206 */
msGetMapContextXMLFloatValue(CPLXMLNode * psRoot,char * pszXMLPath,double * pszField)207 int msGetMapContextXMLFloatValue( CPLXMLNode *psRoot, char *pszXMLPath,
208                                   double *pszField)
209 {
210   char *pszValue;
211 
212   pszValue = (char*)CPLGetXMLValue( psRoot, pszXMLPath, NULL);
213   if(pszValue != NULL) {
214     if( pszField != NULL ) {
215       *pszField = atof(pszValue);
216     } else {
217       return MS_FAILURE;
218     }
219   } else {
220     return MS_FAILURE;
221   }
222 
223   return MS_SUCCESS;
224 }
225 
226 /*
227 ** msLoadMapContextURLELements
228 **
229 ** Take a Node and get the width, height, format and href from it.
230 ** Then put this info in metadatas.
231 */
msLoadMapContextURLELements(CPLXMLNode * psRoot,hashTableObj * metadata,const char * pszMetadataRoot)232 int msLoadMapContextURLELements( CPLXMLNode *psRoot, hashTableObj *metadata,
233                                  const char *pszMetadataRoot)
234 {
235   char *pszMetadataName;
236 
237   if( psRoot == NULL || metadata == NULL || pszMetadataRoot == NULL )
238     return MS_FAILURE;
239 
240   pszMetadataName = (char*) malloc( strlen(pszMetadataRoot) + 10 );
241 
242   sprintf( pszMetadataName, "%s_width", pszMetadataRoot );
243   msGetMapContextXMLHashValue( psRoot, "width", metadata, pszMetadataName );
244 
245   sprintf( pszMetadataName, "%s_height", pszMetadataRoot );
246   msGetMapContextXMLHashValue( psRoot, "height", metadata, pszMetadataName );
247 
248   sprintf( pszMetadataName, "%s_format", pszMetadataRoot );
249   msGetMapContextXMLHashValue( psRoot, "format", metadata, pszMetadataName );
250 
251   sprintf( pszMetadataName, "%s_href", pszMetadataRoot );
252   msGetMapContextXMLHashValue( psRoot, "OnlineResource.xlink:href", metadata,
253                                pszMetadataName );
254 
255   free(pszMetadataName);
256 
257   return MS_SUCCESS;
258 }
259 
260 /* msLoadMapContextKeyword
261 **
262 ** Put the keywords from a XML node and put them in a metadata.
263 ** psRoot should be set to keywordlist
264 */
msLoadMapContextListInMetadata(CPLXMLNode * psRoot,hashTableObj * metadata,char * pszXMLName,char * pszMetadataName,char * pszHashDelimiter)265 int msLoadMapContextListInMetadata( CPLXMLNode *psRoot, hashTableObj *metadata,
266                                     char *pszXMLName, char *pszMetadataName,
267                                     char *pszHashDelimiter)
268 {
269   const char *pszHash, *pszXMLValue;
270   char *pszMetadata;
271 
272   if(psRoot == NULL || psRoot->psChild == NULL ||
273       metadata == NULL || pszMetadataName == NULL || pszXMLName == NULL)
274     return MS_FAILURE;
275 
276   /* Pass from KeywordList to Keyword level */
277   psRoot = psRoot->psChild;
278 
279   /* Loop on all elements and append keywords to the hash table */
280   while (psRoot) {
281     if (psRoot->psChild && strcasecmp(psRoot->pszValue, pszXMLName) == 0) {
282       pszXMLValue = psRoot->psChild->pszValue;
283       pszHash = msLookupHashTable(metadata, pszMetadataName);
284       if (pszHash != NULL) {
285         pszMetadata = (char*)malloc(strlen(pszHash)+
286                                     strlen(pszXMLValue)+2);
287         if(pszHashDelimiter == NULL)
288           sprintf( pszMetadata, "%s%s", pszHash, pszXMLValue );
289         else
290           sprintf( pszMetadata, "%s%s%s", pszHash, pszHashDelimiter,
291                    pszXMLValue );
292         msInsertHashTable(metadata, pszMetadataName, pszMetadata);
293         free(pszMetadata);
294       } else
295         msInsertHashTable(metadata, pszMetadataName, pszXMLValue);
296     }
297     psRoot = psRoot->psNext;
298   }
299 
300   return MS_SUCCESS;
301 }
302 
303 /* msLoadMapContextContactInfo
304 **
305 ** Put the Contact informations from a XML node and put them in a metadata.
306 **
307 */
msLoadMapContextContactInfo(CPLXMLNode * psRoot,hashTableObj * metadata)308 int msLoadMapContextContactInfo( CPLXMLNode *psRoot, hashTableObj *metadata )
309 {
310   if(psRoot == NULL || metadata == NULL)
311     return MS_FAILURE;
312 
313   /* Contact Person primary */
314   msGetMapContextXMLHashValue(psRoot,
315                               "ContactPersonPrimary.ContactPerson",
316                               metadata, "wms_contactperson");
317   msGetMapContextXMLHashValue(psRoot,
318                               "ContactPersonPrimary.ContactOrganization",
319                               metadata, "wms_contactorganization");
320   /* Contact Position */
321   msGetMapContextXMLHashValue(psRoot,
322                               "ContactPosition",
323                               metadata, "wms_contactposition");
324   /* Contact Address */
325   msGetMapContextXMLHashValue(psRoot, "ContactAddress.AddressType",
326                               metadata, "wms_addresstype");
327   msGetMapContextXMLHashValue(psRoot, "ContactAddress.Address",
328                               metadata, "wms_address");
329   msGetMapContextXMLHashValue(psRoot, "ContactAddress.City",
330                               metadata, "wms_city");
331   msGetMapContextXMLHashValue(psRoot, "ContactAddress.StateOrProvince",
332                               metadata, "wms_stateorprovince");
333   msGetMapContextXMLHashValue(psRoot, "ContactAddress.PostCode",
334                               metadata, "wms_postcode");
335   msGetMapContextXMLHashValue(psRoot, "ContactAddress.Country",
336                               metadata, "wms_country");
337 
338   /* Others */
339   msGetMapContextXMLHashValue(psRoot, "ContactVoiceTelephone",
340                               metadata, "wms_contactvoicetelephone");
341   msGetMapContextXMLHashValue(psRoot, "ContactFacsimileTelephone",
342                               metadata, "wms_contactfacsimiletelephone");
343   msGetMapContextXMLHashValue(psRoot, "ContactElectronicMailAddress",
344                               metadata, "wms_contactelectronicmailaddress");
345 
346   return MS_SUCCESS;
347 }
348 
349 /*
350 ** msLoadMapContextLayerFormat
351 **
352 **
353 */
msLoadMapContextLayerFormat(CPLXMLNode * psFormat,layerObj * layer)354 int msLoadMapContextLayerFormat(CPLXMLNode *psFormat, layerObj *layer)
355 {
356   const char *pszValue;
357   char *pszValue1;
358   const char* pszHash;
359 
360   if(psFormat->psChild != NULL &&
361       strcasecmp(psFormat->pszValue, "Format") == 0 ) {
362     if(psFormat->psChild->psNext == NULL)
363       pszValue = psFormat->psChild->pszValue;
364     else
365       pszValue = psFormat->psChild->psNext->pszValue;
366   } else
367     pszValue = NULL;
368 
369   if(pszValue != NULL && strcasecmp(pszValue, "") != 0) {
370     /* wms_format */
371     pszValue1 = (char*)CPLGetXMLValue(psFormat,
372                                       "current", NULL);
373     if(pszValue1 != NULL &&
374         (strcasecmp(pszValue1, "1") == 0 || strcasecmp(pszValue1, "true")==0))
375       msInsertHashTable(&(layer->metadata),
376                         "wms_format", pszValue);
377     /* wms_formatlist */
378     pszHash = msLookupHashTable(&(layer->metadata),
379                                 "wms_formatlist");
380     if(pszHash != NULL) {
381       pszValue1 = (char*)malloc(strlen(pszHash)+
382                                 strlen(pszValue)+2);
383       sprintf(pszValue1, "%s,%s", pszHash, pszValue);
384       msInsertHashTable(&(layer->metadata),
385                         "wms_formatlist", pszValue1);
386       free(pszValue1);
387     } else
388       msInsertHashTable(&(layer->metadata),
389                         "wms_formatlist", pszValue);
390   }
391 
392   /* Make sure selected format is supported or select another
393    * supported format.  Note that we can efficiently do this
394    * only for GIF/PNG/JPEG, can't try to handle all GDAL
395    * formats.
396    */
397   pszValue = msLookupHashTable(&(layer->metadata), "wms_format");
398 
399   if (
400     pszValue && (
401 #if !(defined USE_PNG)
402     strcasecmp(pszValue, "image/png") == 0 ||
403     strcasecmp(pszValue, "PNG") == 0 ||
404 #endif
405 #if !(defined USE_JPEG)
406     strcasecmp(pszValue, "image/jpeg") == 0 ||
407     strcasecmp(pszValue, "JPEG") == 0 ||
408 #endif
409     0 )) {
410     char **papszList=NULL;
411     int i, numformats=0;
412 
413     pszValue = msLookupHashTable(&(layer->metadata),
414                                  "wms_formatlist");
415 
416     papszList = msStringSplit(pszValue, ',', &numformats);
417     for(i=0; i < numformats; i++) {
418       if (
419 #if (defined USE_PNG)
420         strcasecmp(papszList[i], "image/png") == 0 ||
421         strcasecmp(papszList[i], "PNG") == 0 ||
422 #endif
423 #if (defined USE_JPEG)
424         strcasecmp(papszList[i], "image/jpeg") == 0 ||
425         strcasecmp(papszList[i], "JPEG") == 0 ||
426 #endif
427 #ifdef USE_GD_GIF
428         strcasecmp(papszList[i], "image/gif") == 0 ||
429         strcasecmp(papszList[i], "GIF") == 0 ||
430 #endif
431         0 ) {
432         /* Found a match */
433         msInsertHashTable(&(layer->metadata),
434                           "wms_format", papszList[i]);
435         break;
436       }
437     }
438     if(papszList)
439       msFreeCharArray(papszList, numformats);
440 
441   } /* end if unsupported format */
442 
443   return MS_SUCCESS;
444 }
445 
msLoadMapContextLayerStyle(CPLXMLNode * psStyle,layerObj * layer,int nStyle)446 int msLoadMapContextLayerStyle(CPLXMLNode *psStyle, layerObj *layer,
447                                int nStyle)
448 {
449   char *pszValue, *pszValue1, *pszValue2;
450   const char *pszHash;
451   char* pszStyle=NULL;
452   char *pszStyleName;
453   CPLXMLNode *psStyleSLDBody;
454 
455   pszStyleName =(char*)CPLGetXMLValue(psStyle,"Name",NULL);
456   if(pszStyleName == NULL) {
457     pszStyleName = (char*)malloc(20);
458     sprintf(pszStyleName, "Style{%d}", nStyle);
459   } else
460     pszStyleName = msStrdup(pszStyleName);
461 
462   /* wms_style */
463   pszValue = (char*)CPLGetXMLValue(psStyle,"current",NULL);
464   if(pszValue != NULL &&
465       (strcasecmp(pszValue, "1") == 0 ||
466        strcasecmp(pszValue, "true") == 0))
467     msInsertHashTable(&(layer->metadata),
468                       "wms_style", pszStyleName);
469   /* wms_stylelist */
470   pszHash = msLookupHashTable(&(layer->metadata),
471                               "wms_stylelist");
472   if(pszHash != NULL) {
473     pszValue1 = (char*)malloc(strlen(pszHash)+
474                               strlen(pszStyleName)+2);
475     sprintf(pszValue1, "%s,%s", pszHash, pszStyleName);
476     msInsertHashTable(&(layer->metadata),
477                       "wms_stylelist", pszValue1);
478     free(pszValue1);
479   } else
480     msInsertHashTable(&(layer->metadata),
481                       "wms_stylelist", pszStyleName);
482 
483   /* Title */
484   pszStyle = (char*)malloc(strlen(pszStyleName)+20);
485   sprintf(pszStyle,"wms_style_%s_title",pszStyleName);
486 
487   if( msGetMapContextXMLHashValue(psStyle, "Title", &(layer->metadata),
488                                   pszStyle) == MS_FAILURE )
489     msInsertHashTable(&(layer->metadata), pszStyle, layer->name);
490 
491   free(pszStyle);
492 
493   /* SLD */
494   pszStyle = (char*)malloc(strlen(pszStyleName)+15);
495   sprintf(pszStyle, "wms_style_%s_sld", pszStyleName);
496 
497   msGetMapContextXMLHashValueDecode( psStyle, "SLD.OnlineResource.xlink:href",
498                                      &(layer->metadata), pszStyle );
499   free(pszStyle);
500 
501   /* SLDBODY */
502   pszStyle = (char*)malloc(strlen(pszStyleName)+20);
503   sprintf(pszStyle, "wms_style_%s_sld_body", pszStyleName);
504 
505   psStyleSLDBody = CPLGetXMLNode(psStyle, "SLD.StyledLayerDescriptor");
506   /*some clients such as OpenLayers add a name space, which I believe is wrong but
507    added this additional test for compatibility #3115*/
508   if (psStyleSLDBody == NULL)
509     psStyleSLDBody = CPLGetXMLNode(psStyle, "SLD.sld:StyledLayerDescriptor");
510 
511   if(psStyleSLDBody != NULL && &(layer->metadata) != NULL) {
512     pszValue = CPLSerializeXMLTree(psStyleSLDBody);
513     if(pszValue != NULL) {
514       /* Before including SLDBody in the mapfile, we must replace the */
515       /* double quote for single quote. This is to prevent having this: */
516       /* "metadata" "<string attriute="ttt">" */
517       char *c;
518       for(c=pszValue; *c != '\0'; c++)
519         if(*c == '"')
520           *c = '\'';
521       msInsertHashTable(&(layer->metadata), pszStyle, pszValue );
522       msFree(pszValue);
523     }
524   }
525 
526   free(pszStyle);
527 
528   /* LegendURL */
529   pszStyle = (char*) malloc(strlen(pszStyleName) + 25);
530 
531   sprintf( pszStyle, "wms_style_%s_legendurl",
532            pszStyleName);
533   msLoadMapContextURLELements( CPLGetXMLNode(psStyle, "LegendURL"),
534                                &(layer->metadata), pszStyle );
535 
536   free(pszStyle);
537 
538   free(pszStyleName);
539 
540   /*  */
541   /* Add the stylelist to the layer connection */
542   /*  */
543   if(msLookupHashTable(&(layer->metadata),
544                        "wms_stylelist") == NULL) {
545     if(layer->connection)
546       pszValue = msStrdup(layer->connection);
547     else
548       pszValue = msStrdup( "" );
549     pszValue1 = strstr(pszValue, "STYLELIST=");
550     if(pszValue1 != NULL) {
551       pszValue1 += 10;
552       pszValue2 = strchr(pszValue, '&');
553       if(pszValue2 != NULL)
554         pszValue1[pszValue2-pszValue1] = '\0';
555       msInsertHashTable(&(layer->metadata), "wms_stylelist",
556                         pszValue1);
557     }
558     free(pszValue);
559   }
560 
561   /*  */
562   /* Add the style to the layer connection */
563   /*  */
564   if(msLookupHashTable(&(layer->metadata), "wms_style") == NULL) {
565     if(layer->connection)
566       pszValue = msStrdup(layer->connection);
567     else
568       pszValue = msStrdup( "" );
569     pszValue1 = strstr(pszValue, "STYLE=");
570     if(pszValue1 != NULL) {
571       pszValue1 += 6;
572       pszValue2 = strchr(pszValue, '&');
573       if(pszValue2 != NULL)
574         pszValue1[pszValue2-pszValue1] = '\0';
575       msInsertHashTable(&(layer->metadata), "wms_style",
576                         pszValue1);
577     }
578     free(pszValue);
579   }
580 
581   return MS_SUCCESS;
582 }
583 
msLoadMapContextLayerDimension(CPLXMLNode * psDimension,layerObj * layer)584 int msLoadMapContextLayerDimension(CPLXMLNode *psDimension, layerObj *layer)
585 {
586   char *pszValue;
587   const char *pszHash;
588   char *pszDimension=NULL, *pszDimensionName=NULL;
589 
590   pszDimensionName =(char*)CPLGetXMLValue(psDimension,"name",NULL);
591   if(pszDimensionName == NULL) {
592     return MS_FALSE;
593   } else
594     pszDimensionName = msStrdup(pszDimensionName);
595 
596   pszDimension = (char*)malloc(strlen(pszDimensionName)+50);
597 
598   /* wms_dimension: This is the current dimension */
599   pszValue = (char*)CPLGetXMLValue(psDimension, "current", NULL);
600   if(pszValue != NULL && (strcasecmp(pszValue, "1") == 0 ||
601                           strcasecmp(pszValue, "true") == 0))
602     msInsertHashTable(&(layer->metadata),
603                       "wms_dimension", pszDimensionName);
604   /* wms_dimensionlist */
605   pszHash = msLookupHashTable(&(layer->metadata),
606                               "wms_dimensionlist");
607   if(pszHash != NULL) {
608     pszValue = (char*)malloc(strlen(pszHash)+
609                              strlen(pszDimensionName)+2);
610     sprintf(pszValue, "%s,%s", pszHash, pszDimensionName);
611     msInsertHashTable(&(layer->metadata),
612                       "wms_dimensionlist", pszValue);
613     free(pszValue);
614   } else
615     msInsertHashTable(&(layer->metadata),
616                       "wms_dimensionlist", pszDimensionName);
617 
618   /* Units */
619   sprintf(pszDimension, "wms_dimension_%s_units", pszDimensionName);
620   msGetMapContextXMLHashValue(psDimension, "units", &(layer->metadata),
621                               pszDimension);
622 
623   /* UnitSymbol */
624   sprintf(pszDimension, "wms_dimension_%s_unitsymbol", pszDimensionName);
625   msGetMapContextXMLHashValue(psDimension, "unitSymbol", &(layer->metadata),
626                               pszDimension);
627 
628   /* userValue */
629   sprintf(pszDimension, "wms_dimension_%s_uservalue", pszDimensionName);
630   msGetMapContextXMLHashValue(psDimension, "userValue", &(layer->metadata),
631                               pszDimension);
632   if(strcasecmp(pszDimensionName, "time") == 0)
633     msGetMapContextXMLHashValue(psDimension, "userValue", &(layer->metadata),
634                                 "wms_time");
635 
636   /* default */
637   sprintf(pszDimension, "wms_dimension_%s_default", pszDimensionName);
638   msGetMapContextXMLHashValue(psDimension, "default", &(layer->metadata),
639                               pszDimension);
640 
641   /* multipleValues */
642   sprintf(pszDimension, "wms_dimension_%s_multiplevalues", pszDimensionName);
643   msGetMapContextXMLHashValue(psDimension, "multipleValues",&(layer->metadata),
644                               pszDimension);
645 
646   /* nearestValue */
647   sprintf(pszDimension, "wms_dimension_%s_nearestvalue", pszDimensionName);
648   msGetMapContextXMLHashValue(psDimension, "nearestValue", &(layer->metadata),
649                               pszDimension);
650 
651   free(pszDimension);
652 
653   free(pszDimensionName);
654 
655   return MS_SUCCESS;
656 }
657 
658 
659 
660 /*
661 ** msLoadMapContextGeneral
662 **
663 ** Load the General block of the mapcontext document
664 */
msLoadMapContextGeneral(mapObj * map,CPLXMLNode * psGeneral,CPLXMLNode * psMapContext,int nVersion,char * filename)665 int msLoadMapContextGeneral(mapObj *map, CPLXMLNode *psGeneral,
666                             CPLXMLNode *psMapContext, int nVersion,
667                             char *filename)
668 {
669 
670   char *pszProj=NULL;
671   char *pszValue, *pszValue1, *pszValue2;
672   int nTmp;
673 
674   /* Projection */
675   pszValue = (char*)CPLGetXMLValue(psGeneral,
676                                    "BoundingBox.SRS", NULL);
677   if(pszValue != NULL) {
678     if(strncasecmp(pszValue, "AUTO:", 5) == 0) {
679       pszProj = msStrdup(pszValue);
680     } else {
681       pszProj = (char*) malloc(sizeof(char)*(strlen(pszValue)+10));
682       sprintf(pszProj, "init=epsg:%s", pszValue+5);
683     }
684 
685     msInitProjection(&map->projection);
686     map->projection.args[map->projection.numargs] = msStrdup(pszProj);
687     map->projection.numargs++;
688     msProcessProjection(&map->projection);
689 
690     if( (nTmp = GetMapserverUnitUsingProj(&(map->projection))) == -1) {
691       free(pszProj);
692       msSetError( MS_MAPCONTEXTERR,
693                   "Unable to set units for projection '%s'",
694                   "msLoadMapContext()", pszProj );
695       return MS_FAILURE;
696     } else {
697       map->units = nTmp;
698     }
699     free(pszProj);
700   } else {
701     msDebug("Mandatory data General.BoundingBox.SRS missing in %s.",
702             filename);
703   }
704 
705   /* Extent */
706   if( msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.minx",
707                                    &(map->extent.minx)) == MS_FAILURE) {
708     msDebug("Mandatory data General.BoundingBox.minx missing in %s.",
709             filename);
710   }
711   if( msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.miny",
712                                    &(map->extent.miny)) == MS_FAILURE) {
713     msDebug("Mandatory data General.BoundingBox.miny missing in %s.",
714             filename);
715   }
716   if( msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.maxx",
717                                    &(map->extent.maxx)) == MS_FAILURE) {
718     msDebug("Mandatory data General.BoundingBox.maxx missing in %s.",
719             filename);
720   }
721   if( msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.maxy",
722                                    &(map->extent.maxy)) == MS_FAILURE) {
723     msDebug("Mandatory data General.BoundingBox.maxy missing in %s.",
724             filename);
725   }
726 
727   /* Title */
728   if( msGetMapContextXMLHashValue(psGeneral, "Title",
729                                   &(map->web.metadata), "wms_title") == MS_FAILURE) {
730     if ( nVersion >= OWS_1_0_0 )
731       msDebug("Mandatory data General.Title missing in %s.", filename);
732     else {
733       if( msGetMapContextXMLHashValue(psGeneral, "gml:name",
734                                       &(map->web.metadata), "wms_title") == MS_FAILURE ) {
735         if( nVersion < OWS_0_1_7 )
736           msDebug("Mandatory data General.Title missing in %s.", filename);
737         else
738           msDebug("Mandatory data General.gml:name missing in %s.",
739                   filename);
740       }
741     }
742   }
743 
744   /* Name */
745   if( nVersion >= OWS_1_0_0 ) {
746     pszValue = (char*)CPLGetXMLValue(psMapContext,
747                                      "id", NULL);
748     if (pszValue)
749       map->name = msStrdup(pszValue);
750   } else {
751     if(msGetMapContextXMLStringValue(psGeneral, "Name",
752                                      &(map->name)) == MS_FAILURE) {
753       msGetMapContextXMLStringValue(psGeneral, "gml:name",
754                                     &(map->name));
755     }
756   }
757   /* Keyword */
758   if( nVersion >= OWS_1_0_0 ) {
759     msLoadMapContextListInMetadata(
760       CPLGetXMLNode(psGeneral, "KeywordList"),
761       &(map->web.metadata), "KEYWORD", "wms_keywordlist", "," );
762   } else
763     msGetMapContextXMLHashValue(psGeneral, "Keywords",
764                                 &(map->web.metadata), "wms_keywordlist");
765 
766   /* Window */
767   pszValue1 = (char*)CPLGetXMLValue(psGeneral,"Window.width",NULL);
768   pszValue2 = (char*)CPLGetXMLValue(psGeneral,"Window.height",NULL);
769   if(pszValue1 != NULL && pszValue2 != NULL) {
770     map->width = atoi(pszValue1);
771     map->height = atoi(pszValue2);
772   }
773 
774   /* Abstract */
775   if( msGetMapContextXMLHashValue( psGeneral,
776                                    "Abstract", &(map->web.metadata),
777                                    "wms_abstract") == MS_FAILURE ) {
778     msGetMapContextXMLHashValue( psGeneral, "gml:description",
779                                  &(map->web.metadata), "wms_abstract");
780   }
781 
782   /* DataURL */
783   msGetMapContextXMLHashValueDecode(psGeneral,
784                                     "DataURL.OnlineResource.xlink:href",
785                                     &(map->web.metadata), "wms_dataurl");
786 
787   /* LogoURL */
788   /* The logourl have a width, height, format and an URL */
789   msLoadMapContextURLELements( CPLGetXMLNode(psGeneral, "LogoURL"),
790                                &(map->web.metadata), "wms_logourl" );
791 
792   /* DescriptionURL */
793   /* The descriptionurl have a width, height, format and an URL */
794   msLoadMapContextURLELements( CPLGetXMLNode(psGeneral,
795                                "DescriptionURL"),
796                                &(map->web.metadata), "wms_descriptionurl" );
797 
798   /* Contact Info */
799   msLoadMapContextContactInfo(
800     CPLGetXMLNode(psGeneral, "ContactInformation"),
801     &(map->web.metadata) );
802 
803   return MS_SUCCESS;
804 }
805 
806 /*
807 ** msLoadMapContextLayer
808 **
809 ** Load a Layer block from a MapContext document
810 */
msLoadMapContextLayer(mapObj * map,CPLXMLNode * psLayer,int nVersion,char * filename,int unique_layer_names)811 int msLoadMapContextLayer(mapObj *map, CPLXMLNode *psLayer, int nVersion,
812                           char *filename, int unique_layer_names)
813 {
814   char *pszValue;
815   const char *pszHash;
816   char *pszName=NULL;
817   CPLXMLNode *psFormatList, *psFormat, *psStyleList, *psStyle, *psExtension;
818   CPLXMLNode *psDimensionList, *psDimension;
819   int nStyle;
820   layerObj *layer;
821 
822   /* Init new layer */
823   if(msGrowMapLayers(map) == NULL)
824     return MS_FAILURE;
825 
826   layer = (GET_LAYER(map, map->numlayers));
827   initLayer(layer, map);
828   layer->map = (mapObj *)map;
829   layer->type = MS_LAYER_RASTER;
830   /* save the index */
831   GET_LAYER(map, map->numlayers)->index = map->numlayers;
832   map->layerorder[map->numlayers] = map->numlayers;
833   map->numlayers++;
834 
835 
836   /* Status */
837   pszValue = (char*)CPLGetXMLValue(psLayer, "hidden", "1");
838   if((pszValue != NULL) && (atoi(pszValue) == 0 &&
839                             strcasecmp(pszValue, "true") != 0))
840     layer->status = MS_ON;
841   else
842     layer->status = MS_OFF;
843 
844   /* Queryable */
845   pszValue = (char*)CPLGetXMLValue(psLayer, "queryable", "0");
846   if(pszValue !=NULL && (atoi(pszValue) == 1  ||
847                          strcasecmp(pszValue, "true") == 0))
848     layer->template = msStrdup("ttt");
849 
850   /* Name and Title */
851   pszValue = (char*)CPLGetXMLValue(psLayer, "Name", NULL);
852   if(pszValue != NULL) {
853     msInsertHashTable( &(layer->metadata), "wms_name", pszValue );
854 
855     if (unique_layer_names) {
856       pszName = (char*)malloc(sizeof(char)*(strlen(pszValue)+15));
857       sprintf(pszName, "l%d:%s", layer->index, pszValue);
858       layer->name = msStrdup(pszName);
859       free(pszName);
860     } else
861       layer->name  = msStrdup(pszValue);
862   } else {
863     pszName = (char*)malloc(sizeof(char)*15);
864     sprintf(pszName, "l%d:", layer->index);
865     layer->name = msStrdup(pszName);
866     free(pszName);
867   }
868 
869   if(msGetMapContextXMLHashValue(psLayer, "Title", &(layer->metadata),
870                                  "wms_title") == MS_FAILURE) {
871     if(msGetMapContextXMLHashValue(psLayer, "Server.title",
872                                    &(layer->metadata), "wms_title") == MS_FAILURE) {
873       msDebug("Mandatory data Layer.Title missing in %s.", filename);
874     }
875   }
876 
877   /* Server Title */
878   msGetMapContextXMLHashValue(psLayer, "Server.title", &(layer->metadata),  "wms_server_title");
879 
880   /* Abstract */
881   msGetMapContextXMLHashValue(psLayer, "Abstract", &(layer->metadata),
882                               "wms_abstract");
883 
884   /* DataURL */
885   if(nVersion <= OWS_0_1_4) {
886     msGetMapContextXMLHashValueDecode(psLayer,
887                                       "DataURL.OnlineResource.xlink:href",
888                                       &(layer->metadata), "wms_dataurl");
889   } else {
890     /* The DataURL have a width, height, format and an URL */
891     /* Width and height are not used, but they are included to */
892     /* be consistent with the spec. */
893     msLoadMapContextURLELements( CPLGetXMLNode(psLayer, "DataURL"),
894                                  &(layer->metadata), "wms_dataurl" );
895   }
896 
897   /* The MetadataURL have a width, height, format and an URL */
898   /* Width and height are not used, but they are included to */
899   /* be consistent with the spec. */
900   msLoadMapContextURLELements( CPLGetXMLNode(psLayer, "MetadataURL"),
901                                &(layer->metadata), "wms_metadataurl" );
902 
903 
904   /* MinScale && MaxScale */
905   pszValue = (char*)CPLGetXMLValue(psLayer, "sld:MinScaleDenominator", NULL);
906   if(pszValue != NULL) {
907     layer->minscaledenom = atof(pszValue);
908   }
909 
910   pszValue = (char*)CPLGetXMLValue(psLayer, "sld:MaxScaleDenominator", NULL);
911   if(pszValue != NULL) {
912     layer->maxscaledenom = atof(pszValue);
913   }
914 
915   /*  */
916   /* Server */
917   /*  */
918   if(nVersion >= OWS_0_1_4) {
919     if(msGetMapContextXMLStringValueDecode(psLayer,
920                                            "Server.OnlineResource.xlink:href",
921                                            &(layer->connection)) == MS_FAILURE) {
922       msSetError(MS_MAPCONTEXTERR,
923                  "Mandatory data Server.OnlineResource.xlink:href missing in %s.",
924                  "msLoadMapContext()", filename);
925       return MS_FAILURE;
926     } else {
927       msGetMapContextXMLHashValueDecode(psLayer,
928                                         "Server.OnlineResource.xlink:href",
929                                         &(layer->metadata), "wms_onlineresource");
930       layer->connectiontype = MS_WMS;
931     }
932   } else {
933     if(msGetMapContextXMLStringValueDecode(psLayer,
934                                            "Server.onlineResource",
935                                            &(layer->connection)) == MS_FAILURE) {
936       msSetError(MS_MAPCONTEXTERR,
937                  "Mandatory data Server.onlineResource missing in %s.",
938                  "msLoadMapContext()", filename);
939       return MS_FAILURE;
940     } else {
941       msGetMapContextXMLHashValueDecode(psLayer, "Server.onlineResource",
942                                         &(layer->metadata), "wms_onlineresource");
943       layer->connectiontype = MS_WMS;
944     }
945   }
946 
947   if(nVersion >= OWS_0_1_4) {
948     if(msGetMapContextXMLHashValue(psLayer, "Server.version",
949                                    &(layer->metadata), "wms_server_version") == MS_FAILURE) {
950       msSetError(MS_MAPCONTEXTERR,
951                  "Mandatory data Server.version missing in %s.",
952                  "msLoadMapContext()", filename);
953       return MS_FAILURE;
954     }
955   } else {
956     if(msGetMapContextXMLHashValue(psLayer, "Server.wmtver",
957                                    &(layer->metadata), "wms_server_version") == MS_FAILURE) {
958       msSetError(MS_MAPCONTEXTERR,
959                  "Mandatory data Server.wmtver missing in %s.",
960                  "msLoadMapContext()", filename);
961       return MS_FAILURE;
962     }
963   }
964 
965   /* Projection */
966   msLoadMapContextListInMetadata( psLayer, &(layer->metadata),
967                                   "SRS", "wms_srs", " " );
968 
969   pszHash = msLookupHashTable(&(layer->metadata), "wms_srs");
970   if(((pszHash == NULL) || (strcasecmp(pszHash, "") == 0)) &&
971       map->projection.numargs != 0) {
972     char* pszProj = map->projection.args[map->projection.numargs-1];
973 
974     if(pszProj != NULL) {
975       if(strncasecmp(pszProj, "AUTO:", 5) == 0) {
976         msInsertHashTable(&(layer->metadata),"wms_srs", pszProj);
977       } else {
978         if(strlen(pszProj) > 10) {
979           pszProj = (char*) malloc(sizeof(char) * (strlen(pszProj)));
980           sprintf( pszProj, "EPSG:%s",
981                    map->projection.args[map->projection.numargs-1]+10);
982           msInsertHashTable(&(layer->metadata),"wms_srs", pszProj);
983         } else {
984           msDebug("Unable to set data for layer wms_srs from this"
985                   " value %s.",
986                   pszProj);
987         }
988       }
989       msFree(pszProj);
990     }
991   }
992 
993   /*  */
994   /* Format */
995   /*  */
996   if( nVersion >= OWS_0_1_4 ) {
997     psFormatList = CPLGetXMLNode(psLayer, "FormatList");
998   } else {
999     psFormatList = psLayer;
1000   }
1001 
1002   if(psFormatList != NULL) {
1003     for(psFormat = psFormatList->psChild;
1004         psFormat != NULL;
1005         psFormat = psFormat->psNext) {
1006       msLoadMapContextLayerFormat(psFormat, layer);
1007     }
1008 
1009   } /* end FormatList parsing */
1010 
1011   /* Style */
1012   if( nVersion >= OWS_0_1_4 ) {
1013     psStyleList = CPLGetXMLNode(psLayer, "StyleList");
1014   } else {
1015     psStyleList = psLayer;
1016   }
1017 
1018   if(psStyleList != NULL) {
1019     nStyle = 0;
1020     for(psStyle = psStyleList->psChild;
1021         psStyle != NULL;
1022         psStyle = psStyle->psNext) {
1023       if(strcasecmp(psStyle->pszValue, "Style") == 0) {
1024         nStyle++;
1025         msLoadMapContextLayerStyle(psStyle, layer, nStyle);
1026       }
1027     }
1028   }
1029 
1030   /* Dimension */
1031   psDimensionList = CPLGetXMLNode(psLayer, "DimensionList");
1032   if(psDimensionList != NULL) {
1033     for(psDimension = psDimensionList->psChild;
1034         psDimension != NULL;
1035         psDimension = psDimension->psNext) {
1036       if(strcasecmp(psDimension->pszValue, "Dimension") == 0) {
1037         msLoadMapContextLayerDimension(psDimension, layer);
1038       }
1039     }
1040   }
1041 
1042   /* Extension */
1043   psExtension = CPLGetXMLNode(psLayer, "Extension");
1044   if (psExtension != NULL) {
1045     pszValue = (char*)CPLGetXMLValue(psExtension, "ol:opacity", NULL);
1046     if(pszValue != NULL) {
1047       if(!layer->compositer) {
1048         layer->compositer = msSmallMalloc(sizeof(LayerCompositer));
1049         initLayerCompositer(layer->compositer);
1050       }
1051       layer->compositer->opacity = atof(pszValue)*100;
1052     }
1053   }
1054 
1055   return MS_SUCCESS;
1056 }
1057 
1058 #endif
1059 
1060 
1061 
1062 /* msLoadMapContextURL()
1063 **
1064 ** load an OGC Web Map Context format from an URL
1065 **
1066 ** Take a map object and a URL to a conect file in arguments
1067 */
1068 
msLoadMapContextURL(mapObj * map,char * urlfilename,int unique_layer_names)1069 int msLoadMapContextURL(mapObj *map, char *urlfilename, int unique_layer_names)
1070 {
1071 #if defined(USE_WMS_LYR)
1072   char *pszTmpFile = NULL;
1073   int status = 0;
1074 
1075   if (!map || !urlfilename) {
1076     msSetError(MS_MAPCONTEXTERR,
1077                "Invalid map or url given.",
1078                "msGetMapContextURL()");
1079     return MS_FAILURE;
1080   }
1081 
1082   pszTmpFile = msTmpFile(map, map->mappath, NULL, "context.xml");
1083   if (msHTTPGetFile(urlfilename, pszTmpFile, &status,-1, 0, 0, 0) ==  MS_SUCCESS) {
1084     return msLoadMapContext(map, pszTmpFile, unique_layer_names);
1085   } else {
1086     msSetError(MS_MAPCONTEXTERR,
1087                "Could not open context file %s.",
1088                "msGetMapContextURL()", urlfilename);
1089     return MS_FAILURE;
1090   }
1091 
1092 #else
1093   msSetError(MS_MAPCONTEXTERR,
1094              "Not implemented since Map Context is not enabled.",
1095              "msGetMapContextURL()");
1096   return MS_FAILURE;
1097 #endif
1098 }
1099 /* msLoadMapContext()
1100 **
1101 ** Get a mapfile from a OGC Web Map Context format
1102 **
1103 ** Take as first map object and a file in arguments
1104 ** If The 2nd aregument unique_layer_names is set to MS_TRUE, the layer
1105 ** name created would be unique and be prefixed with an l plus the layers's index
1106 ** (eg l:1:park. l:2:road ...). If It is set to MS_FALSE, the layer name
1107 ** would be the same name as the layer name in the context
1108 */
msLoadMapContext(mapObj * map,char * filename,int unique_layer_names)1109 int msLoadMapContext(mapObj *map, char *filename, int unique_layer_names)
1110 {
1111 #if defined(USE_WMS_LYR)
1112   char *pszWholeText, *pszValue;
1113   CPLXMLNode *psRoot, *psMapContext, *psLayer, *psLayerList, *psChild;
1114   char szPath[MS_MAXPATHLEN];
1115   int nVersion=-1;
1116   char szVersionBuf[OWS_VERSION_MAXLEN];
1117 
1118   /*  */
1119   /* Load the raw XML file */
1120   /*  */
1121 
1122   pszWholeText = msGetMapContextFileText(
1123                    msBuildPath(szPath, map->mappath, filename));
1124   if(pszWholeText == NULL) {
1125     msSetError( MS_MAPCONTEXTERR, "Unable to read %s",
1126                 "msLoadMapContext()", filename );
1127     return MS_FAILURE;
1128   }
1129 
1130   if( ( strstr( pszWholeText, "<WMS_Viewer_Context" ) == NULL ) &&
1131       ( strstr( pszWholeText, "<View_Context" ) == NULL ) &&
1132       ( strstr( pszWholeText, "<ViewContext" ) == NULL ) )
1133 
1134   {
1135     free( pszWholeText );
1136     msSetError( MS_MAPCONTEXTERR, "Not a Map Context file (%s)",
1137                 "msLoadMapContext()", filename );
1138     return MS_FAILURE;
1139   }
1140 
1141   /*  */
1142   /* Convert to XML parse tree. */
1143   /*  */
1144   psRoot = CPLParseXMLString( pszWholeText );
1145   free( pszWholeText );
1146 
1147   /* We assume parser will report errors via CPL. */
1148   if( psRoot == NULL ) {
1149     msSetError( MS_MAPCONTEXTERR, "Invalid XML file (%s)",
1150                 "msLoadMapContext()", filename );
1151     if(psRoot != NULL)
1152       CPLDestroyXMLNode(psRoot);
1153 
1154     return MS_FAILURE;
1155   }
1156 
1157   /*  */
1158   /* Valid the MapContext file and get the root of the document */
1159   /*  */
1160   psChild = psRoot;
1161   psMapContext = NULL;
1162   while( psChild != NULL ) {
1163     if( psChild->eType == CXT_Element &&
1164         (EQUAL(psChild->pszValue,"WMS_Viewer_Context") ||
1165          EQUAL(psChild->pszValue,"View_Context") ||
1166          EQUAL(psChild->pszValue,"ViewContext")) ) {
1167       psMapContext = psChild;
1168       break;
1169     } else {
1170       psChild = psChild->psNext;
1171     }
1172   }
1173 
1174   if( psMapContext == NULL ) {
1175     CPLDestroyXMLNode(psRoot);
1176     msSetError( MS_MAPCONTEXTERR, "Invalid Map Context File (%s)",
1177                 "msLoadMapContext()", filename );
1178     return MS_FAILURE;
1179   }
1180 
1181   /* Fetch document version number */
1182   pszValue = (char*)CPLGetXMLValue(psMapContext,
1183                                    "version", NULL);
1184   if( !pszValue ) {
1185     msDebug( "msLoadMapContext(): Mandatory data version missing in %s, assuming 0.1.4.",
1186              filename );
1187     pszValue = "0.1.4";
1188   }
1189 
1190   nVersion = msOWSParseVersionString(pszValue);
1191 
1192   /* Make sure this is a supported version */
1193   switch (nVersion) {
1194     case OWS_0_1_2:
1195     case OWS_0_1_4:
1196     case OWS_0_1_7:
1197     case OWS_1_0_0:
1198     case OWS_1_1_0:
1199       /* All is good, this is a supported version. */
1200       break;
1201     default:
1202       /* Not a supported version */
1203       msSetError(MS_MAPCONTEXTERR,
1204                  "This version of Map Context is not supported (%s).",
1205                  "msLoadMapContext()", pszValue);
1206       CPLDestroyXMLNode(psRoot);
1207       return MS_FAILURE;
1208   }
1209 
1210   /* Reformat and save Version in metadata */
1211   msInsertHashTable( &(map->web.metadata), "wms_context_version",
1212                      msOWSGetVersionString(nVersion, szVersionBuf));
1213 
1214   if( nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) {
1215     if( msGetMapContextXMLHashValue(psMapContext, "fid",
1216                                     &(map->web.metadata), "wms_context_fid") == MS_FAILURE ) {
1217       msDebug("Mandatory data fid missing in %s.", filename);
1218     }
1219   }
1220 
1221   /*  */
1222   /* Load the General bloc */
1223   /*  */
1224   psChild = CPLGetXMLNode( psMapContext, "General" );
1225   if( psChild == NULL ) {
1226     CPLDestroyXMLNode(psRoot);
1227     msSetError(MS_MAPCONTEXTERR,
1228                "The Map Context document provided (%s) does not contain any "
1229                "General elements.",
1230                "msLoadMapContext()", filename);
1231     return MS_FAILURE;
1232   }
1233 
1234   if( msLoadMapContextGeneral(map, psChild, psMapContext,
1235                               nVersion, filename) == MS_FAILURE ) {
1236     CPLDestroyXMLNode(psRoot);
1237     return MS_FAILURE;
1238   }
1239 
1240   /*  */
1241   /* Load the bloc LayerList */
1242   /*  */
1243   psLayerList = CPLGetXMLNode(psMapContext, "LayerList");
1244   if( psLayerList != NULL ) {
1245     for(psLayer = psLayerList->psChild;
1246         psLayer != NULL;
1247         psLayer = psLayer->psNext) {
1248       if(EQUAL(psLayer->pszValue, "Layer")) {
1249         if( msLoadMapContextLayer(map, psLayer, nVersion,
1250                                   filename, unique_layer_names) == MS_FAILURE ) {
1251           CPLDestroyXMLNode(psRoot);
1252           return MS_FAILURE;
1253         }
1254       }/* end Layer parsing */
1255     }/* for */
1256   }
1257 
1258   CPLDestroyXMLNode(psRoot);
1259 
1260   return MS_SUCCESS;
1261 
1262 #else
1263   msSetError(MS_MAPCONTEXTERR,
1264              "Not implemented since Map Context is not enabled.",
1265              "msGetMapContext()");
1266   return MS_FAILURE;
1267 #endif
1268 }
1269 
1270 
1271 /* msSaveMapContext()
1272 **
1273 ** Save a mapfile into the OGC Web Map Context format
1274 **
1275 ** Take a map object and a file in arguments
1276 */
msSaveMapContext(mapObj * map,char * filename)1277 int msSaveMapContext(mapObj *map, char *filename)
1278 {
1279 #if defined(USE_WMS_LYR)
1280   VSILFILE *stream;
1281   char szPath[MS_MAXPATHLEN];
1282   int nStatus;
1283 
1284   /* open file */
1285   if(filename != NULL && strlen(filename) > 0) {
1286     stream = fopen(msBuildPath(szPath, map->mappath, filename), "wb");
1287     if(!stream) {
1288       msSetError(MS_IOERR, "(%s)", "msSaveMapContext()", filename);
1289       return(MS_FAILURE);
1290     }
1291   } else {
1292     msSetError(MS_IOERR, "Filename is undefined.", "msSaveMapContext()");
1293     return MS_FAILURE;
1294   }
1295 
1296   nStatus = msWriteMapContext(map, stream);
1297 
1298   fclose(stream);
1299 
1300   return nStatus;
1301 #else
1302   msSetError(MS_MAPCONTEXTERR,
1303              "Not implemented since Map Context is not enabled.",
1304              "msSaveMapContext()");
1305   return MS_FAILURE;
1306 #endif
1307 }
1308 
1309 
1310 
msWriteMapContext(mapObj * map,FILE * stream)1311 int msWriteMapContext(mapObj *map, FILE *stream)
1312 {
1313 #if defined(USE_WMS_LYR)
1314   const char * version;
1315   char *pszEPSG;
1316   char * tabspace=NULL, *pszChar,*pszSLD=NULL,*pszURL,*pszSLD2=NULL;
1317   char *pszStyle, *pszStyleItem, *pszSLDBody;
1318   char *pszEncodedVal;
1319   int i, nValue, nVersion=OWS_VERSION_NOTSET;
1320   /* Dimension element */
1321   char *pszDimension;
1322   const char *pszDimUserValue=NULL, *pszDimUnits=NULL, *pszDimDefault=NULL;
1323   const char *pszDimNearValue=NULL, *pszDimUnitSymbol=NULL;
1324   const char *pszDimMultiValue=NULL;
1325   int bDimensionList = 0;
1326 
1327   /* Decide which version we're going to return... */
1328   version = msLookupHashTable(&(map->web.metadata), "wms_context_version");
1329   if(version == NULL)
1330     version = "1.1.0";
1331 
1332   nVersion = msOWSParseVersionString(version);
1333   if (nVersion == OWS_VERSION_BADFORMAT)
1334     return MS_FAILURE;  /* msSetError() already called. */
1335 
1336   /* Make sure this is a supported version */
1337   /* Note that we don't write 0.1.2 even if we read it. */
1338   switch (nVersion) {
1339     case OWS_0_1_4:
1340     case OWS_0_1_7:
1341     case OWS_1_0_0:
1342     case OWS_1_1_0:
1343       /* All is good, this is a supported version. */
1344       break;
1345     default:
1346       /* Not a supported version */
1347       msSetError(MS_MAPCONTEXTERR,
1348                  "This version of Map Context is not supported (%s).",
1349                  "msSaveMapContext()", version);
1350       return MS_FAILURE;
1351   }
1352 
1353   /* file header */
1354   msIO_fprintf( stream, "<?xml version='1.0' encoding=\"UTF-8\" standalone=\"no\" ?>\n");
1355 
1356   /* set the WMS_Viewer_Context information */
1357   pszEncodedVal = msEncodeHTMLEntities(version);
1358   if(nVersion >= OWS_1_0_0) {
1359     msIO_fprintf( stream, "<ViewContext version=\"%s\"", pszEncodedVal );
1360   } else if(nVersion >= OWS_0_1_7) {
1361     msIO_fprintf( stream, "<View_Context version=\"%s\"", pszEncodedVal );
1362 
1363   } else { /* 0.1.4 */
1364     msIO_fprintf( stream, "<WMS_Viewer_Context version=\"%s\"", pszEncodedVal );
1365   }
1366   msFree(pszEncodedVal);
1367 
1368   if ( nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0 ) {
1369     msOWSPrintEncodeMetadata(stream, &(map->web.metadata), NULL,
1370                              "wms_context_fid", OWS_NOERR," fid=\"%s\"","0");
1371   }
1372   if ( nVersion >= OWS_1_0_0 )
1373     msOWSPrintEncodeParam(stream, "MAP.NAME", map->name, OWS_NOERR,
1374                           " id=\"%s\"", NULL);
1375 
1376   msIO_fprintf( stream, " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
1377   msIO_fprintf( stream, " xmlns:ogc=\"http://www.opengis.net/ogc\"");
1378 
1379   if( nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0 ) {
1380     msIO_fprintf( stream, " xmlns:gml=\"http://www.opengis.net/gml\"");
1381   }
1382   if( nVersion >= OWS_1_0_0 ) {
1383     msIO_fprintf( stream, " xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
1384     msIO_fprintf( stream, " xmlns=\"http://www.opengis.net/context\"");
1385     msIO_fprintf( stream, " xmlns:sld=\"http://www.opengis.net/sld\"");
1386     pszEncodedVal = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
1387     if( nVersion >= OWS_1_1_0 )
1388       msIO_fprintf( stream,
1389                     " xsi:schemaLocation=\"http://www.opengis.net/context %s/context/1.1.0/context.xsd\">\n",
1390                     pszEncodedVal);
1391     else
1392       msIO_fprintf( stream,
1393                     " xsi:schemaLocation=\"http://www.opengis.net/context %s/context/1.0.0/context.xsd\">\n",
1394                     pszEncodedVal);
1395     msFree(pszEncodedVal);
1396   } else {
1397     msIO_fprintf( stream, " xmlns:xlink=\"http://www.w3.org/TR/xlink\"");
1398 
1399     pszEncodedVal = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
1400     msIO_fprintf( stream, " xsi:noNamespaceSchemaLocation=\"%s/contexts/",
1401                   pszEncodedVal );
1402     msFree(pszEncodedVal);
1403     pszEncodedVal = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
1404     msIO_fprintf( stream, "%s/context.xsd\">\n", pszEncodedVal);
1405     msFree(pszEncodedVal);
1406   }
1407 
1408   /* set the General information */
1409   msIO_fprintf( stream, "  <General>\n" );
1410 
1411   /* Window */
1412   if( map->width != -1 || map->height != -1 )
1413     msIO_fprintf( stream, "    <Window width=\"%d\" height=\"%d\"/>\n",
1414                   map->width, map->height );
1415 
1416   /* Bounding box corners and spatial reference system */
1417   if(tabspace)
1418     free(tabspace);
1419   tabspace = msStrdup("    ");
1420   msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "MO", MS_TRUE, &pszEPSG);
1421   msIO_fprintf( stream,
1422                 "%s<!-- Bounding box corners and spatial reference system -->\n",
1423                 tabspace );
1424   if(!pszEPSG || (strcasecmp(pszEPSG, "(null)") == 0))
1425     msIO_fprintf(stream, "<!-- WARNING: Mandatory data 'projection' was missing in this context. -->\n");
1426 
1427   pszEncodedVal = msEncodeHTMLEntities(pszEPSG);
1428   msIO_fprintf( stream, "%s<BoundingBox SRS=\"%s\" minx=\"%f\" miny=\"%f\" maxx=\"%f\" maxy=\"%f\"/>\n",
1429                 tabspace, pszEncodedVal, map->extent.minx, map->extent.miny,
1430                 map->extent.maxx, map->extent.maxy );
1431   msFree(pszEncodedVal);
1432   msFree(pszEPSG);
1433 
1434   /* Title, name */
1435   if( nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0 ) {
1436     msOWSPrintEncodeParam(stream, "MAP.NAME", map->name, OWS_NOERR,
1437                           "    <gml:name>%s</gml:name>\n", NULL);
1438   } else {
1439     if (nVersion < OWS_0_1_7)
1440       msOWSPrintEncodeParam(stream, "MAP.NAME", map->name, OWS_NOERR,
1441                             "    <Name>%s</Name>\n", NULL);
1442 
1443     msIO_fprintf( stream, "%s<!-- Title of Context -->\n", tabspace );
1444     msOWSPrintEncodeMetadata(stream, &(map->web.metadata),
1445                              NULL, "wms_title", OWS_WARN,
1446                              "    <Title>%s</Title>\n", map->name);
1447   }
1448 
1449   /* keyword */
1450   if (nVersion >= OWS_1_0_0) {
1451     if (msLookupHashTable(&(map->web.metadata),"wms_keywordlist")!=NULL) {
1452       char **papszKeywords;
1453       int nKeywords, iKey;
1454 
1455       const char* pszValue = msLookupHashTable(&(map->web.metadata),
1456                                    "wms_keywordlist");
1457       papszKeywords = msStringSplit(pszValue, ',', &nKeywords);
1458       if(nKeywords > 0 && papszKeywords) {
1459         msIO_fprintf( stream, "    <KeywordList>\n");
1460         for(iKey=0; iKey<nKeywords; iKey++) {
1461           pszEncodedVal = msEncodeHTMLEntities(papszKeywords[iKey]);
1462           msIO_fprintf( stream, "      <Keyword>%s</Keyword>\n",
1463                         pszEncodedVal);
1464           msFree(pszEncodedVal);
1465         }
1466         msIO_fprintf( stream, "    </KeywordList>\n");
1467       }
1468     }
1469   } else
1470     msOWSPrintEncodeMetadataList(stream, &(map->web.metadata), NULL,
1471                                  "wms_keywordlist",
1472                                  "    <Keywords>\n", "    </Keywords>\n",
1473                                  "      %s\n", NULL);
1474 
1475   /* abstract */
1476   if( nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0 ) {
1477     msOWSPrintEncodeMetadata(stream, &(map->web.metadata),
1478                              NULL, "wms_abstract", OWS_NOERR,
1479                              "    <gml:description>%s</gml:description>\n", NULL);
1480   } else {
1481     msOWSPrintEncodeMetadata(stream, &(map->web.metadata),
1482                              NULL, "wms_abstract", OWS_NOERR,
1483                              "    <Abstract>%s</Abstract>\n", NULL);
1484   }
1485 
1486   /* LogoURL */
1487   /* The LogoURL have a width, height, format and an URL */
1488   msOWSPrintURLType(stream, &(map->web.metadata), "MO", "logourl",
1489                     OWS_NOERR, NULL, "LogoURL", NULL, " width=\"%s\"",
1490                     " height=\"%s\""," format=\"%s\"",
1491                     "      <OnlineResource xlink:type=\"simple\" xlink:href=\"%s\"/>\n",
1492                     MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE,
1493                     NULL, NULL, NULL, NULL, NULL, "    ");
1494 
1495   /* DataURL */
1496   msOWSPrintEncodeMetadata(stream, &(map->web.metadata),
1497                            NULL, "wms_dataurl", OWS_NOERR,
1498                            "    <DataURL>\n      <OnlineResource xlink:type=\"simple\" xlink:href=\"%s\"/>\n    </DataURL>\n", NULL);
1499 
1500   /* DescriptionURL */
1501   /* The DescriptionURL have a width, height, format and an URL */
1502   /* The metadata is structured like this: "width height format url" */
1503   msOWSPrintURLType(stream, &(map->web.metadata), "MO", "descriptionurl",
1504                     OWS_NOERR, NULL, "DescriptionURL", NULL, " width=\"%s\"",
1505                     " height=\"%s\""," format=\"%s\"",
1506                     "      <OnlineResource xlink:type=\"simple\" xlink:href=\"%s\"/>\n",
1507                     MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE,
1508                     NULL, NULL, NULL, NULL, NULL, "    ");
1509 
1510   /* Contact Info */
1511   msOWSPrintContactInfo( stream, tabspace, OWS_1_1_0, &(map->web.metadata), "MO" );
1512 
1513   /* Close General */
1514   msIO_fprintf( stream, "  </General>\n" );
1515   free(tabspace);
1516 
1517   /* Set the layer list */
1518   msIO_fprintf(stream, "  <LayerList>\n");
1519 
1520   /* Loop on all layer   */
1521   for(i=0; i<map->numlayers; i++) {
1522     if(GET_LAYER(map, i)->status != MS_DELETE && GET_LAYER(map, i)->connectiontype == MS_WMS) {
1523       const char* pszValue;
1524       char* pszValueMod;
1525       const char* pszCurrent;
1526       if(GET_LAYER(map, i)->status == MS_OFF)
1527         nValue = 1;
1528       else
1529         nValue = 0;
1530       msIO_fprintf(stream, "    <Layer queryable=\"%d\" hidden=\"%d\">\n",
1531                    msIsLayerQueryable(GET_LAYER(map, i)), nValue);
1532 
1533       /*  */
1534       /* Server definition */
1535       /*  */
1536       if(nVersion < OWS_1_0_0 )
1537         msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1538                                  NULL, "wms_server_version", OWS_WARN,
1539                                  "      <Server service=\"WMS\" version=\"%s\" ",
1540                                  "1.0.0");
1541       else
1542         msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1543                                  NULL, "wms_server_version", OWS_WARN,
1544                                  "      <Server service=\"OGC:WMS\" version=\"%s\" ",
1545                                  "1.0.0");
1546 
1547       if(msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "MO", "server_title"))
1548         msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1549                                  NULL, "wms_server_title", OWS_NOERR,
1550                                  "title=\"%s\">\n", "");
1551 
1552       else if(GET_LAYER(map, i)->name)
1553         msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1554                                  NULL, "wms_title", OWS_NOERR,
1555                                  "title=\"%s\">\n", GET_LAYER(map, i)->name);
1556       else {
1557         msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1558                                  NULL, "wms_title", OWS_NOERR,
1559                                  "title=\"%s\">\n", "");
1560       }
1561 
1562       /* Get base url of the online resource to be the default value */
1563       if(GET_LAYER(map, i)->connection)
1564         pszValueMod = msStrdup( GET_LAYER(map, i)->connection );
1565       else
1566         pszValueMod = msStrdup( "" );
1567       pszChar = strchr(pszValueMod, '?');
1568       if( pszChar )
1569         pszValueMod[pszChar - pszValueMod] = '\0';
1570       if(msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1571                                   NULL, "wms_onlineresource", OWS_WARN,
1572                                   "        <OnlineResource xlink:type=\"simple\" xlink:href=\"%s\"/>\n",
1573                                   pszValueMod) == OWS_WARN)
1574         msIO_fprintf(stream, "<!-- wms_onlineresource not set, using base URL"
1575                      " , but probably not what you want -->\n");
1576       msIO_fprintf(stream, "      </Server>\n");
1577       if(pszValueMod)
1578         free(pszValueMod);
1579 
1580       /*  */
1581       /* Layer information */
1582       /*  */
1583       msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1584                                NULL, "wms_name", OWS_WARN,
1585                                "      <Name>%s</Name>\n",
1586                                GET_LAYER(map, i)->name);
1587       msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1588                                NULL, "wms_title", OWS_WARN,
1589                                "      <Title>%s</Title>\n",
1590                                GET_LAYER(map, i)->name);
1591       msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1592                                NULL, "wms_abstract", OWS_NOERR,
1593                                "      <Abstract>%s</Abstract>\n",
1594                                NULL);
1595 
1596       /* DataURL */
1597       if(nVersion <= OWS_0_1_4) {
1598         msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1599                                  NULL, "wms_dataurl", OWS_NOERR,
1600                                  "      <DataURL>%s</DataURL>\n",
1601                                  NULL);
1602       } else {
1603         /* The DataURL have a width, height, format and an URL */
1604         /* The metadata will be structured like this:  */
1605         /* "width height format url" */
1606         /* Note: in version 0.1.7 the width and height are not included  */
1607         /* in the Context file, but they are included in the metadata for */
1608         /* for consistency with the URLType. */
1609         msOWSPrintURLType(stream, &(GET_LAYER(map, i)->metadata), "MO",
1610                           "dataurl", OWS_NOERR, NULL, "DataURL", NULL,
1611                           " width=\"%s\"", " height=\"%s\"",
1612                           " format=\"%s\"",
1613                           "        <OnlineResource xlink:type=\"simple\""
1614                           " xlink:href=\"%s\"/>\n",
1615                           MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE,
1616                           MS_TRUE, NULL, NULL, NULL,NULL,NULL, "      ");
1617       }
1618 
1619       /* MetadataURL */
1620       /* The MetadataURL have a width, height, format and an URL */
1621       /* The metadata will be structured like this:  */
1622       /* "width height format url" */
1623       msOWSPrintURLType(stream, &(GET_LAYER(map, i)->metadata), "MO",
1624                         "metadataurl", OWS_NOERR, NULL, "MetadataURL",NULL,
1625                         " width=\"%s\"", " height=\"%s\""," format=\"%s\"",
1626                         "        <OnlineResource xlink:type=\"simple\""
1627                         " xlink:href=\"%s\"/>\n",
1628                         MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE,
1629                         MS_TRUE, NULL, NULL, NULL, NULL, NULL, "      ");
1630 
1631       /* MinScale && MaxScale */
1632       if(nVersion >= OWS_1_1_0 && GET_LAYER(map, i)->minscaledenom > 0)
1633         msIO_fprintf(stream,
1634                      "      <sld:MinScaleDenominator>%g</sld:MinScaleDenominator>\n",
1635                      GET_LAYER(map, i)->minscaledenom);
1636       if(nVersion >= OWS_1_1_0 && GET_LAYER(map, i)->maxscaledenom > 0)
1637         msIO_fprintf(stream,
1638                      "      <sld:MaxScaleDenominator>%g</sld:MaxScaleDenominator>\n",
1639                      GET_LAYER(map, i)->maxscaledenom);
1640 
1641       /* Layer SRS */
1642       msOWSGetEPSGProj(&(GET_LAYER(map, i)->projection),
1643                                          &(GET_LAYER(map, i)->metadata),
1644                                          "MO", MS_FALSE, &pszEPSG);
1645       if(pszEPSG && (strcasecmp(pszEPSG, "(null)") != 0)) {
1646         pszEncodedVal = msEncodeHTMLEntities(pszEPSG);
1647         msIO_fprintf(stream, "      <SRS>%s</SRS>\n", pszEncodedVal);
1648         msFree(pszEncodedVal);
1649       }
1650       msFree(pszEPSG);
1651 
1652       /* Format */
1653       if(msLookupHashTable(&(GET_LAYER(map, i)->metadata),"wms_formatlist")==NULL &&
1654           msLookupHashTable(&(GET_LAYER(map, i)->metadata),"wms_format")==NULL) {
1655         pszURL = NULL;
1656         if(GET_LAYER(map, i)->connection)
1657           pszURL = msStrdup( GET_LAYER(map, i)->connection );
1658         else
1659           pszURL = msStrdup( "" );
1660         pszValueMod = pszURL;
1661         pszValueMod = strstr( pszValueMod, "FORMAT=" );
1662         if( pszValueMod ) {
1663           pszValueMod += 7;
1664           pszChar = strchr(pszValueMod, '&');
1665           if( pszChar )
1666             pszValueMod[pszChar - pszValueMod] = '\0';
1667           if(strcasecmp(pszValueMod, "") != 0) {
1668             pszEncodedVal = msEncodeHTMLEntities(pszValueMod);
1669             msIO_fprintf( stream, "      <FormatList>\n");
1670             msIO_fprintf(stream,"        <Format>%s</Format>\n",pszValueMod);
1671             msIO_fprintf( stream, "      </FormatList>\n");
1672             msFree(pszEncodedVal);
1673           }
1674         }
1675         if(pszURL)
1676           free(pszURL);
1677       } else {
1678         char **papszFormats;
1679         int numFormats, nForm;
1680 
1681         pszValue = msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1682                                      "wms_formatlist");
1683         if(!pszValue)
1684           pszValue = msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1685                                        "wms_format");
1686         pszCurrent = msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1687                                        "wms_format");
1688 
1689         papszFormats = msStringSplit(pszValue, ',', &numFormats);
1690         if(numFormats > 0 && papszFormats) {
1691           msIO_fprintf( stream, "      <FormatList>\n");
1692           for(nForm=0; nForm<numFormats; nForm++) {
1693             pszEncodedVal =msEncodeHTMLEntities(papszFormats[nForm]);
1694             if(pszCurrent && (strcasecmp(papszFormats[nForm],
1695                                          pszCurrent) == 0))
1696               msIO_fprintf( stream,
1697                             "        <Format current=\"1\">%s</Format>\n",
1698                             pszEncodedVal);
1699             else
1700               msIO_fprintf( stream, "        <Format>%s</Format>\n",
1701                             pszEncodedVal);
1702             msFree(pszEncodedVal);
1703           }
1704           msIO_fprintf( stream, "      </FormatList>\n");
1705         }
1706         if(papszFormats)
1707           msFreeCharArray(papszFormats, numFormats);
1708       }
1709       /* Style */
1710       /* First check the stylelist */
1711       pszValue = msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1712                                    "wms_stylelist");
1713       while( pszValue && *pszValue == ' ' )
1714           pszValue ++;
1715       if(pszValue == NULL || strlen(pszValue) < 1) {
1716         /* Check if the style is in the connection URL */
1717         pszURL = "";
1718         if(GET_LAYER(map, i)->connection)
1719           pszURL = msStrdup( GET_LAYER(map, i)->connection );
1720         else
1721           pszURL = msStrdup( "" );
1722         pszValueMod = pszURL;
1723         /* Grab the STYLES in the URL */
1724         pszValueMod = strstr( pszValueMod, "STYLES=" );
1725         if( pszValueMod ) {
1726           pszValueMod += 7;
1727           pszChar = strchr(pszValueMod, '&');
1728           if( pszChar )
1729             pszValueMod[pszChar - pszValueMod] = '\0';
1730 
1731           /* Check the SLD string from the URL */
1732           if(GET_LAYER(map, i)->connection)
1733             pszSLD2 = msStrdup(GET_LAYER(map, i)->connection);
1734           else
1735             pszSLD2 = msStrdup( "" );
1736           if(pszSLD2) {
1737             pszSLD = strstr(pszSLD2, "SLD=");
1738             pszSLDBody = strstr(pszSLD2, "SLD_BODY=");
1739           } else {
1740             pszSLD = NULL;
1741             pszSLDBody = NULL;
1742           }
1743           /* Check SLD */
1744           if( pszSLD ) {
1745             pszChar = strchr(pszSLD, '&');
1746             if( pszChar )
1747               pszSLD[pszChar - pszSLD] = '\0';
1748             pszSLD += 4;
1749           }
1750           /* Check SLDBody  */
1751           if( pszSLDBody ) {
1752             pszChar = strchr(pszSLDBody, '&');
1753             if( pszChar )
1754               pszSLDBody[pszChar - pszSLDBody] = '\0';
1755             pszSLDBody += 9;
1756           }
1757           if( (pszValueMod && (strcasecmp(pszValueMod, "") != 0)) ||
1758               (pszSLD && (strcasecmp(pszSLD, "") != 0)) ||
1759               (pszSLDBody && (strcasecmp(pszSLDBody, "") != 0))) {
1760             /* Write Name and Title */
1761             msIO_fprintf( stream, "      <StyleList>\n");
1762             msIO_fprintf( stream, "        <Style current=\"1\">\n");
1763             if( pszValueMod && (strcasecmp(pszValueMod, "") != 0)) {
1764               pszEncodedVal = msEncodeHTMLEntities(pszValueMod);
1765               msIO_fprintf(stream, "          <Name>%s</Name>\n",
1766                            pszEncodedVal);
1767               msIO_fprintf(stream,"          <Title>%s</Title>\n",
1768                            pszEncodedVal);
1769               msFree(pszEncodedVal);
1770             }
1771             /* Write the SLD string from the URL */
1772             if( pszSLD && (strcasecmp(pszSLD, "") != 0)) {
1773               pszEncodedVal = msEncodeHTMLEntities(pszSLD);
1774               msIO_fprintf( stream, "          <SLD>\n" );
1775               msIO_fprintf( stream,
1776                             "            <OnlineResource xlink:type=\"simple\" ");
1777               msIO_fprintf(stream,"xlink:href=\"%s\"/>",
1778                            pszEncodedVal);
1779               msIO_fprintf( stream, "          </SLD>\n" );
1780               free(pszEncodedVal);
1781             } else if(pszSLDBody && (strcasecmp(pszSLDBody, "") != 0)) {
1782               msIO_fprintf( stream, "          <SLD>\n" );
1783               msIO_fprintf( stream, "            %s\n",pszSLDBody);
1784               msIO_fprintf( stream, "          </SLD>\n" );
1785             }
1786             msIO_fprintf( stream, "        </Style>\n");
1787             msIO_fprintf( stream, "      </StyleList>\n");
1788           }
1789           if(pszSLD2) {
1790             free(pszSLD2);
1791             pszSLD2 = NULL;
1792           }
1793         }
1794         if(pszURL) {
1795           free(pszURL);
1796           pszURL = NULL;
1797         }
1798       } else {
1799         const char* pszCurrent;
1800         /* If the style information is not in the connection URL, */
1801         /* read the metadata. */
1802         pszValue = msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1803                                      "wms_stylelist");
1804         pszCurrent = msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1805                                        "wms_style");
1806         msIO_fprintf( stream, "      <StyleList>\n");
1807         /* Loop in each style in the style list */
1808         while(pszValue != NULL) {
1809           pszStyle = msStrdup(pszValue);
1810           pszChar = strchr(pszStyle, ',');
1811           if(pszChar != NULL)
1812             pszStyle[pszChar - pszStyle] = '\0';
1813           if(strcasecmp(pszStyle, "") == 0)
1814             continue;
1815 
1816           if(pszCurrent && (strcasecmp(pszStyle, pszCurrent) == 0))
1817             msIO_fprintf( stream,"        <Style current=\"1\">\n" );
1818           else
1819             msIO_fprintf( stream, "        <Style>\n" );
1820 
1821           /* Write SLDURL if it is in the metadata */
1822           pszStyleItem = (char*)malloc(strlen(pszStyle)+10+10);
1823           sprintf(pszStyleItem, "wms_style_%s_sld", pszStyle);
1824           if(msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1825                                pszStyleItem) != NULL) {
1826             msIO_fprintf(stream, "          <SLD>\n");
1827             msOWSPrintEncodeMetadata(stream,
1828                                      &(GET_LAYER(map, i)->metadata),
1829                                      NULL, pszStyleItem,
1830                                      OWS_NOERR,
1831                                      "            <OnlineResource xlink:type=\"simple\" xlink:href=\"%s\"/>\n",
1832                                      NULL);
1833             msIO_fprintf(stream, "          </SLD>\n");
1834             free(pszStyleItem);
1835           } else {
1836             /* If the URL is not there, check for SLDBody */
1837             sprintf(pszStyleItem, "wms_style_%s_sld_body", pszStyle);
1838             if(msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1839                                  pszStyleItem) != NULL) {
1840               msIO_fprintf(stream, "          <SLD>\n");
1841               msOWSPrintMetadata(stream,&(GET_LAYER(map, i)->metadata),
1842                                  NULL, pszStyleItem, OWS_NOERR,
1843                                  "            %s\n", NULL);
1844               msIO_fprintf(stream, "          </SLD>\n");
1845               free(pszStyleItem);
1846             } else {
1847               /* If the SLD is not specified, then write the */
1848               /* name, Title and LegendURL */
1849               free(pszStyleItem);
1850               /* Name */
1851               pszEncodedVal = msEncodeHTMLEntities(pszStyle);
1852               msIO_fprintf(stream, "          <Name>%s</Name>\n",
1853                            pszEncodedVal);
1854               msFree(pszEncodedVal);
1855               pszStyleItem = (char*)malloc(strlen(pszStyle)+10+8);
1856               sprintf(pszStyleItem, "wms_style_%s_title",pszStyle);
1857               /* Title */
1858               msOWSPrintEncodeMetadata(stream,
1859                                        &(GET_LAYER(map, i)->metadata),
1860                                        NULL, pszStyleItem,
1861                                        OWS_NOERR,
1862                                        "          <Title>%s</Title>\n",
1863                                        NULL);
1864               free(pszStyleItem);
1865 
1866               /* LegendURL */
1867               pszStyleItem = (char*)malloc(strlen(pszStyle)+10+20);
1868               sprintf(pszStyleItem, "style_%s_legendurl",
1869                       pszStyle);
1870               msOWSPrintURLType(stream, &(GET_LAYER(map, i)->metadata),
1871                                 "M", pszStyleItem, OWS_NOERR, NULL,
1872                                 "LegendURL", NULL, " width=\"%s\"",
1873                                 " height=\"%s\""," format=\"%s\"",
1874                                 "            <OnlineResource "
1875                                 "xlink:type=\"simple\""
1876                                 " xlink:href=\"%s\"/>\n          ",
1877                                 MS_FALSE, MS_FALSE, MS_FALSE,
1878                                 MS_FALSE, MS_TRUE, NULL, NULL,
1879                                 NULL, NULL, NULL, "          ");
1880               free(pszStyleItem);
1881             }
1882           }
1883 
1884           msIO_fprintf( stream,"        </Style>\n" );
1885 
1886           free(pszStyle);
1887           pszValue = strchr(pszValue, ',');
1888           if(pszValue)
1889             pszValue++;
1890         }
1891         msIO_fprintf( stream, "      </StyleList>\n");
1892       }
1893 
1894       /* Dimension element */;
1895       pszCurrent = NULL;
1896 
1897       pszValue = msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1898                                    "wms_dimensionlist");
1899       pszCurrent = msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1900                                      "wms_dimension");
1901       while(pszValue != NULL) {
1902         /* Extract the dimension name from the list */
1903         pszDimension = msStrdup(pszValue);
1904         pszChar = strchr(pszDimension, ',');
1905         if(pszChar != NULL)
1906           pszDimension[pszChar - pszDimension] = '\0';
1907         if(strcasecmp(pszDimension, "") == 0) {
1908           free(pszDimension);
1909           pszValue = strchr(pszValue, ',');
1910           if(pszValue)
1911             pszValue++;
1912           continue;
1913         }
1914 
1915         /* From the dimension list, extract the required dimension */
1916         msOWSGetDimensionInfo(GET_LAYER(map, i), pszDimension,
1917                               &pszDimUserValue, &pszDimUnits,
1918                               &pszDimDefault, &pszDimNearValue,
1919                               &pszDimUnitSymbol, &pszDimMultiValue);
1920 
1921         if(pszDimUserValue == NULL || pszDimUnits == NULL ||
1922             pszDimUnitSymbol == NULL) {
1923           free(pszDimension);
1924           pszValue = strchr(pszValue, ',');
1925           if(pszValue)
1926             pszValue++;
1927           continue;
1928         }
1929 
1930         if(!bDimensionList) {
1931           bDimensionList = 1;
1932           msIO_fprintf( stream, "      <DimensionList>\n");
1933         }
1934 
1935         /* name */
1936         msIO_fprintf( stream, "        <Dimension name=\"%s\"",
1937                       pszDimension);
1938         /* units */
1939         msIO_fprintf( stream, " units=\"%s\"",      pszDimUnits);
1940         /* unitSymbol */
1941         msIO_fprintf( stream, " unitSymbol=\"%s\"", pszDimUnitSymbol);
1942         /* userValue */
1943         msIO_fprintf( stream, " userValue=\"%s\"",  pszDimUserValue);
1944         /* default */
1945         if(pszDimDefault)
1946           msIO_fprintf( stream, " default=\"%s\"", pszDimDefault);
1947         /* multipleValues */
1948         if(pszDimMultiValue)
1949           msIO_fprintf(stream, " multipleValues=\"%s\"",
1950                        pszDimMultiValue);
1951         /* nearestValue */
1952         if(pszDimNearValue)
1953           msIO_fprintf( stream," nearestValue=\"%s\"",pszDimNearValue);
1954 
1955         if(pszCurrent && strcasecmp(pszDimension, pszCurrent) == 0)
1956           msIO_fprintf( stream, " current=\"1\"");
1957 
1958         msIO_fprintf( stream, "/>\n");
1959 
1960         free(pszDimension);
1961         pszValue = strchr(pszValue, ',');
1962         if(pszValue)
1963           pszValue++;
1964       }
1965 
1966       if(bDimensionList) {
1967         msIO_fprintf( stream, "      </DimensionList>\n");
1968         bDimensionList = 0;
1969       }
1970 
1971       msIO_fprintf(stream, "    </Layer>\n");
1972     }
1973   }
1974 
1975   /* Close layer list */
1976   msIO_fprintf(stream, "  </LayerList>\n");
1977   /* Close Map Context */
1978 
1979   if(nVersion >= OWS_1_0_0) {
1980     msIO_fprintf(stream, "</ViewContext>\n");
1981   } else if(nVersion >= OWS_0_1_7) {
1982     msIO_fprintf(stream, "</View_Context>\n");
1983   } else { /* 0.1.4 */
1984     msIO_fprintf(stream, "</WMS_Viewer_Context>\n");
1985   }
1986 
1987   return MS_SUCCESS;
1988 #else
1989   msSetError(MS_MAPCONTEXTERR,
1990              "Not implemented since Map Context is not enabled.",
1991              "msWriteMapContext()");
1992   return MS_FAILURE;
1993 #endif
1994 }
1995 
1996 
1997