Coverage Report

Created: 2025-08-28 06:57

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