Coverage Report

Created: 2026-10-28 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MapServer/src/mapcontext.c
Line
Count
Source
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 if (strncasecmp(pszValue, "EPSG:", 5) == 0) {
641
      pszProj = (char *)malloc(sizeof(char) * (strlen(pszValue) + 10));
642
      sprintf(pszProj, "init=epsg:%s", pszValue + 5);
643
    } else {
644
      pszProj = msStrdup(pszValue);
645
    }
646
647
    msFreeProjection(&map->projection);
648
    msInitProjection(&map->projection);
649
    map->projection.args[map->projection.numargs] = msStrdup(pszProj);
650
    map->projection.numargs++;
651
    msProcessProjection(&map->projection);
652
653
    if ((nTmp = GetMapserverUnitUsingProj(&(map->projection))) == -1) {
654
      msSetError(MS_MAPCONTEXTERR, "Unable to set units for projection '%s'",
655
                 "msLoadMapContext()", pszProj);
656
      free(pszProj);
657
      return MS_FAILURE;
658
    } else {
659
      map->units = nTmp;
660
    }
661
    free(pszProj);
662
  } else {
663
    msDebug("Mandatory data General.BoundingBox.SRS missing in %s.", filename);
664
  }
665
666
  /* Extent */
667
  if (msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.minx",
668
                                   &(map->extent.minx)) == MS_FAILURE) {
669
    msDebug("Mandatory data General.BoundingBox.minx missing in %s.", filename);
670
  }
671
  if (msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.miny",
672
                                   &(map->extent.miny)) == MS_FAILURE) {
673
    msDebug("Mandatory data General.BoundingBox.miny missing in %s.", filename);
674
  }
675
  if (msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.maxx",
676
                                   &(map->extent.maxx)) == MS_FAILURE) {
677
    msDebug("Mandatory data General.BoundingBox.maxx missing in %s.", filename);
678
  }
679
  if (msGetMapContextXMLFloatValue(psGeneral, "BoundingBox.maxy",
680
                                   &(map->extent.maxy)) == MS_FAILURE) {
681
    msDebug("Mandatory data General.BoundingBox.maxy missing in %s.", filename);
682
  }
683
684
  /* Title */
685
  if (msGetMapContextXMLHashValue(psGeneral, "Title", &(map->web.metadata),
686
                                  "wms_title") == MS_FAILURE) {
687
    if (nVersion >= OWS_1_0_0)
688
      msDebug("Mandatory data General.Title missing in %s.", filename);
689
    else {
690
      if (msGetMapContextXMLHashValue(psGeneral, "gml:name",
691
                                      &(map->web.metadata),
692
                                      "wms_title") == MS_FAILURE) {
693
        if (nVersion < OWS_0_1_7)
694
          msDebug("Mandatory data General.Title missing in %s.", filename);
695
        else
696
          msDebug("Mandatory data General.gml:name missing in %s.", filename);
697
      }
698
    }
699
  }
700
701
  /* Name */
702
  if (nVersion >= OWS_1_0_0) {
703
    pszValue = (char *)CPLGetXMLValue(psMapContext, "id", NULL);
704
    if (pszValue) {
705
      msFree(map->name);
706
      map->name = msStrdup(pszValue);
707
    }
708
  } else {
709
    char *pszMapName = NULL;
710
    if (msGetMapContextXMLStringValue(psGeneral, "Name", &pszMapName) ==
711
        MS_FAILURE) {
712
      msGetMapContextXMLStringValue(psGeneral, "gml:name", &pszMapName);
713
    }
714
    if (pszMapName) {
715
      msFree(map->name);
716
      map->name = pszMapName;
717
    }
718
  }
719
  /* Keyword */
720
  if (nVersion >= OWS_1_0_0) {
721
    msLoadMapContextListInMetadata(CPLGetXMLNode(psGeneral, "KeywordList"),
722
                                   &(map->web.metadata), "KEYWORD",
723
                                   "wms_keywordlist", ",");
724
  } else
725
    msGetMapContextXMLHashValue(psGeneral, "Keywords", &(map->web.metadata),
726
                                "wms_keywordlist");
727
728
  /* Window */
729
  pszValue1 = (char *)CPLGetXMLValue(psGeneral, "Window.width", NULL);
730
  pszValue2 = (char *)CPLGetXMLValue(psGeneral, "Window.height", NULL);
731
  if (pszValue1 != NULL && pszValue2 != NULL) {
732
    map->width = atoi(pszValue1);
733
    map->height = atoi(pszValue2);
734
  }
735
736
  /* Abstract */
737
  if (msGetMapContextXMLHashValue(psGeneral, "Abstract", &(map->web.metadata),
738
                                  "wms_abstract") == MS_FAILURE) {
739
    msGetMapContextXMLHashValue(psGeneral, "gml:description",
740
                                &(map->web.metadata), "wms_abstract");
741
  }
742
743
  /* DataURL */
744
  msGetMapContextXMLHashValueDecode(psGeneral,
745
                                    "DataURL.OnlineResource.xlink:href",
746
                                    &(map->web.metadata), "wms_dataurl");
747
748
  /* LogoURL */
749
  /* The logourl have a width, height, format and an URL */
750
  msLoadMapContextURLELements(CPLGetXMLNode(psGeneral, "LogoURL"),
751
                              &(map->web.metadata), "wms_logourl");
752
753
  /* DescriptionURL */
754
  /* The descriptionurl have a width, height, format and an URL */
755
  msLoadMapContextURLELements(CPLGetXMLNode(psGeneral, "DescriptionURL"),
756
                              &(map->web.metadata), "wms_descriptionurl");
757
758
  /* Contact Info */
759
  msLoadMapContextContactInfo(CPLGetXMLNode(psGeneral, "ContactInformation"),
760
                              &(map->web.metadata));
761
762
  return MS_SUCCESS;
763
}
764
765
/*
766
** msLoadMapContextLayer
767
**
768
** Load a Layer block from a MapContext document
769
*/
770
int msLoadMapContextLayer(mapObj *map, CPLXMLNode *psLayer, int nVersion,
771
                          const char *filename, int unique_layer_names) {
772
  char *pszValue;
773
  const char *pszHash;
774
  char *pszName = NULL;
775
  CPLXMLNode *psFormatList, *psFormat, *psStyleList, *psStyle, *psExtension;
776
  CPLXMLNode *psDimensionList, *psDimension;
777
  int nStyle;
778
  layerObj *layer;
779
780
  /* Init new layer */
781
  if (msGrowMapLayers(map) == NULL)
782
    return MS_FAILURE;
783
784
  layer = (GET_LAYER(map, map->numlayers));
785
  initLayer(layer, map);
786
  layer->map = (mapObj *)map;
787
  layer->type = MS_LAYER_RASTER;
788
  /* save the index */
789
  GET_LAYER(map, map->numlayers)->index = map->numlayers;
790
  map->layerorder[map->numlayers] = map->numlayers;
791
  map->numlayers++;
792
793
  /* Status */
794
  pszValue = (char *)CPLGetXMLValue(psLayer, "hidden", "1");
795
  if ((pszValue != NULL) &&
796
      (atoi(pszValue) == 0 && strcasecmp(pszValue, "true") != 0))
797
    layer->status = MS_ON;
798
  else
799
    layer->status = MS_OFF;
800
801
  /* Queryable */
802
  pszValue = (char *)CPLGetXMLValue(psLayer, "queryable", "0");
803
  if (pszValue != NULL &&
804
      (atoi(pszValue) == 1 || strcasecmp(pszValue, "true") == 0))
805
    layer->template = msStrdup("ttt");
806
807
  /* Name and Title */
808
  pszValue = (char *)CPLGetXMLValue(psLayer, "Name", NULL);
809
  if (pszValue != NULL) {
810
    msInsertHashTable(&(layer->metadata), "wms_name", pszValue);
811
812
    if (unique_layer_names) {
813
      pszName = (char *)malloc(sizeof(char) * (strlen(pszValue) + 15));
814
      sprintf(pszName, "l%d:%s", layer->index, pszValue);
815
      layer->name = msStrdup(pszName);
816
      free(pszName);
817
    } else
818
      layer->name = msStrdup(pszValue);
819
  } else {
820
    pszName = (char *)malloc(sizeof(char) * 15);
821
    sprintf(pszName, "l%d:", layer->index);
822
    layer->name = msStrdup(pszName);
823
    free(pszName);
824
  }
825
826
  if (msGetMapContextXMLHashValue(psLayer, "Title", &(layer->metadata),
827
                                  "wms_title") == MS_FAILURE) {
828
    if (msGetMapContextXMLHashValue(psLayer, "Server.title", &(layer->metadata),
829
                                    "wms_title") == MS_FAILURE) {
830
      msDebug("Mandatory data Layer.Title missing in %s.", filename);
831
    }
832
  }
833
834
  /* Server Title */
835
  msGetMapContextXMLHashValue(psLayer, "Server.title", &(layer->metadata),
836
                              "wms_server_title");
837
838
  /* Abstract */
839
  msGetMapContextXMLHashValue(psLayer, "Abstract", &(layer->metadata),
840
                              "wms_abstract");
841
842
  /* DataURL */
843
  if (nVersion <= OWS_0_1_4) {
844
    msGetMapContextXMLHashValueDecode(psLayer,
845
                                      "DataURL.OnlineResource.xlink:href",
846
                                      &(layer->metadata), "wms_dataurl");
847
  } else {
848
    /* The DataURL have a width, height, format and an URL */
849
    /* Width and height are not used, but they are included to */
850
    /* be consistent with the spec. */
851
    msLoadMapContextURLELements(CPLGetXMLNode(psLayer, "DataURL"),
852
                                &(layer->metadata), "wms_dataurl");
853
  }
854
855
  /* The MetadataURL have a width, height, format and an URL */
856
  /* Width and height are not used, but they are included to */
857
  /* be consistent with the spec. */
858
  msLoadMapContextURLELements(CPLGetXMLNode(psLayer, "MetadataURL"),
859
                              &(layer->metadata), "wms_metadataurl");
860
861
  /* MinScale && MaxScale */
862
  pszValue = (char *)CPLGetXMLValue(psLayer, "sld:MinScaleDenominator", NULL);
863
  if (pszValue != NULL) {
864
    layer->minscaledenom = atof(pszValue);
865
  }
866
867
  pszValue = (char *)CPLGetXMLValue(psLayer, "sld:MaxScaleDenominator", NULL);
868
  if (pszValue != NULL) {
869
    layer->maxscaledenom = atof(pszValue);
870
  }
871
872
  /*  */
873
  /* Server */
874
  /*  */
875
  if (nVersion >= OWS_0_1_4) {
876
    if (msGetMapContextXMLStringValueDecode(
877
            psLayer, "Server.OnlineResource.xlink:href",
878
            &(layer->connection)) == MS_FAILURE) {
879
      msSetError(
880
          MS_MAPCONTEXTERR,
881
          "Mandatory data Server.OnlineResource.xlink:href missing in %s.",
882
          "msLoadMapContext()", filename);
883
      return MS_FAILURE;
884
    } else {
885
      msGetMapContextXMLHashValueDecode(
886
          psLayer, "Server.OnlineResource.xlink:href", &(layer->metadata),
887
          "wms_onlineresource");
888
      layer->connectiontype = MS_WMS;
889
    }
890
  } else {
891
    if (msGetMapContextXMLStringValueDecode(psLayer, "Server.onlineResource",
892
                                            &(layer->connection)) ==
893
        MS_FAILURE) {
894
      msSetError(MS_MAPCONTEXTERR,
895
                 "Mandatory data Server.onlineResource missing in %s.",
896
                 "msLoadMapContext()", filename);
897
      return MS_FAILURE;
898
    } else {
899
      msGetMapContextXMLHashValueDecode(psLayer, "Server.onlineResource",
900
                                        &(layer->metadata),
901
                                        "wms_onlineresource");
902
      layer->connectiontype = MS_WMS;
903
    }
904
  }
905
906
  if (nVersion >= OWS_0_1_4) {
907
    if (msGetMapContextXMLHashValue(psLayer, "Server.version",
908
                                    &(layer->metadata),
909
                                    "wms_server_version") == MS_FAILURE) {
910
      msSetError(MS_MAPCONTEXTERR,
911
                 "Mandatory data Server.version missing in %s.",
912
                 "msLoadMapContext()", filename);
913
      return MS_FAILURE;
914
    }
915
  } else {
916
    if (msGetMapContextXMLHashValue(psLayer, "Server.wmtver",
917
                                    &(layer->metadata),
918
                                    "wms_server_version") == MS_FAILURE) {
919
      msSetError(MS_MAPCONTEXTERR,
920
                 "Mandatory data Server.wmtver missing in %s.",
921
                 "msLoadMapContext()", filename);
922
      return MS_FAILURE;
923
    }
924
  }
925
926
  /* Projection */
927
  msLoadMapContextListInMetadata(psLayer, &(layer->metadata), "SRS", "wms_srs",
928
                                 " ");
929
930
  pszHash = msLookupHashTable(&(layer->metadata), "wms_srs");
931
  if (((pszHash == NULL) || (strcasecmp(pszHash, "") == 0)) &&
932
      map->projection.numargs != 0) {
933
    const char *pszLastProjArg =
934
        map->projection.args[map->projection.numargs - 1];
935
936
    if (pszLastProjArg != NULL) {
937
      if (strncasecmp(pszLastProjArg, "AUTO:", 5) == 0) {
938
        msInsertHashTable(&(layer->metadata), "wms_srs", pszLastProjArg);
939
      } else {
940
        if (strncasecmp(pszLastProjArg, "+init=epsg:", strlen("+init=epsg:")) ==
941
            0) {
942
          const size_t nSRSSize =
943
              strlen("EPSG:") + strlen(pszLastProjArg + strlen("+init=epsg:")) +
944
              1;
945
          char *pszSRS = (char *)malloc(nSRSSize);
946
          snprintf(pszSRS, nSRSSize, "EPSG:%s",
947
                   pszLastProjArg + strlen("+init=epsg:"));
948
          msInsertHashTable(&(layer->metadata), "wms_srs", pszSRS);
949
          msFree(pszSRS);
950
        } else {
951
          msDebug("Unable to set data for layer wms_srs from this"
952
                  " value %s.",
953
                  pszLastProjArg);
954
        }
955
      }
956
    }
957
  }
958
959
  /*  */
960
  /* Format */
961
  /*  */
962
  if (nVersion >= OWS_0_1_4) {
963
    psFormatList = CPLGetXMLNode(psLayer, "FormatList");
964
  } else {
965
    psFormatList = psLayer;
966
  }
967
968
  if (psFormatList != NULL) {
969
    for (psFormat = psFormatList->psChild; psFormat != NULL;
970
         psFormat = psFormat->psNext) {
971
      msLoadMapContextLayerFormat(psFormat, layer);
972
    }
973
974
  } /* end FormatList parsing */
975
976
  /* Style */
977
  if (nVersion >= OWS_0_1_4) {
978
    psStyleList = CPLGetXMLNode(psLayer, "StyleList");
979
  } else {
980
    psStyleList = psLayer;
981
  }
982
983
  if (psStyleList != NULL) {
984
    nStyle = 0;
985
    for (psStyle = psStyleList->psChild; psStyle != NULL;
986
         psStyle = psStyle->psNext) {
987
      if (strcasecmp(psStyle->pszValue, "Style") == 0) {
988
        nStyle++;
989
        msLoadMapContextLayerStyle(psStyle, layer, nStyle);
990
      }
991
    }
992
  }
993
994
  /* Dimension */
995
  psDimensionList = CPLGetXMLNode(psLayer, "DimensionList");
996
  if (psDimensionList != NULL) {
997
    for (psDimension = psDimensionList->psChild; psDimension != NULL;
998
         psDimension = psDimension->psNext) {
999
      if (strcasecmp(psDimension->pszValue, "Dimension") == 0) {
1000
        msLoadMapContextLayerDimension(psDimension, layer);
1001
      }
1002
    }
1003
  }
1004
1005
  /* Extension */
1006
  psExtension = CPLGetXMLNode(psLayer, "Extension");
1007
  if (psExtension != NULL) {
1008
    pszValue = (char *)CPLGetXMLValue(psExtension, "ol:opacity", NULL);
1009
    if (pszValue != NULL) {
1010
      if (!layer->compositer) {
1011
        layer->compositer = msSmallMalloc(sizeof(LayerCompositer));
1012
        initLayerCompositer(layer->compositer);
1013
      }
1014
      layer->compositer->opacity = atof(pszValue) * 100;
1015
    }
1016
  }
1017
1018
  return MS_SUCCESS;
1019
}
1020
1021
#endif
1022
1023
/* msLoadMapContextURL()
1024
**
1025
** load an OGC Web Map Context format from an URL
1026
**
1027
** Take a map object and a URL to a connect file in arguments
1028
*/
1029
1030
int msLoadMapContextURL(mapObj *map, char *urlfilename,
1031
0
                        int unique_layer_names) {
1032
#if defined(USE_WMS_LYR)
1033
  char *pszTmpFile = NULL;
1034
  int status = 0;
1035
1036
  if (!map || !urlfilename) {
1037
    msSetError(MS_MAPCONTEXTERR, "Invalid map or url given.",
1038
               "msGetMapContextURL()");
1039
    return MS_FAILURE;
1040
  }
1041
1042
  pszTmpFile = msTmpFile(map, map->mappath, NULL, "context.xml");
1043
  if (msHTTPGetFile(urlfilename, pszTmpFile, &status, -1, 0, 0, 0) ==
1044
      MS_SUCCESS) {
1045
    return msLoadMapContext(map, pszTmpFile, unique_layer_names);
1046
  } else {
1047
    msSetError(MS_MAPCONTEXTERR, "Could not open context file %s.",
1048
               "msGetMapContextURL()", urlfilename);
1049
    return MS_FAILURE;
1050
  }
1051
1052
#else
1053
0
  msSetError(MS_MAPCONTEXTERR,
1054
0
             "Not implemented since Map Context is not enabled.",
1055
0
             "msGetMapContextURL()");
1056
0
  return MS_FAILURE;
1057
0
#endif
1058
0
}
1059
/* msLoadMapContext()
1060
**
1061
** Get a mapfile from a OGC Web Map Context format
1062
**
1063
** Take as first map object and a file in arguments
1064
** If The 2nd aregument unique_layer_names is set to MS_TRUE, the layer
1065
** name created would be unique and be prefixed with an l plus the layers's
1066
*index
1067
** (eg l:1:park. l:2:road ...). If It is set to MS_FALSE, the layer name
1068
** would be the same name as the layer name in the context
1069
*/
1070
int msLoadMapContext(mapObj *map, const char *filename,
1071
0
                     int unique_layer_names) {
1072
#if defined(USE_WMS_LYR)
1073
  char *pszWholeText, *pszValue;
1074
  CPLXMLNode *psRoot, *psMapContext, *psLayer, *psLayerList, *psChild;
1075
  char szPath[MS_MAXPATHLEN];
1076
  int nVersion = -1;
1077
  char szVersionBuf[OWS_VERSION_MAXLEN];
1078
1079
  const char *ms_contextfile_pattern = CPLGetConfigOption(
1080
      "MS_CONTEXTFILE_PATTERN", MS_DEFAULT_CONTEXTFILE_PATTERN);
1081
  if (msEvalRegex(ms_contextfile_pattern, filename) != MS_TRUE) {
1082
    msSetError(MS_REGEXERR, "Filename validation failed.",
1083
               "msLoadMapContext()");
1084
    return MS_FAILURE;
1085
  }
1086
1087
  /*  */
1088
  /* Load the raw XML file */
1089
  /*  */
1090
1091
  pszWholeText =
1092
      msGetMapContextFileText(msBuildPath(szPath, map->mappath, filename));
1093
  if (pszWholeText == NULL) {
1094
    msSetError(MS_MAPCONTEXTERR, "Unable to read %s", "msLoadMapContext()",
1095
               filename);
1096
    return MS_FAILURE;
1097
  }
1098
1099
  if ((strstr(pszWholeText, "<WMS_Viewer_Context") == NULL) &&
1100
      (strstr(pszWholeText, "<View_Context") == NULL) &&
1101
      (strstr(pszWholeText, "<ViewContext") == NULL))
1102
1103
  {
1104
    free(pszWholeText);
1105
    msSetError(MS_MAPCONTEXTERR, "Not a Map Context file (%s)",
1106
               "msLoadMapContext()", filename);
1107
    return MS_FAILURE;
1108
  }
1109
1110
  /*  */
1111
  /* Convert to XML parse tree. */
1112
  /*  */
1113
  psRoot = CPLParseXMLString(pszWholeText);
1114
  free(pszWholeText);
1115
1116
  /* We assume parser will report errors via CPL. */
1117
  if (psRoot == NULL) {
1118
    msSetError(MS_MAPCONTEXTERR, "Invalid XML file (%s)", "msLoadMapContext()",
1119
               filename);
1120
    return MS_FAILURE;
1121
  }
1122
1123
  /*  */
1124
  /* Valid the MapContext file and get the root of the document */
1125
  /*  */
1126
  psChild = psRoot;
1127
  psMapContext = NULL;
1128
  while (psChild != NULL) {
1129
    if (psChild->eType == CXT_Element &&
1130
        (EQUAL(psChild->pszValue, "WMS_Viewer_Context") ||
1131
         EQUAL(psChild->pszValue, "View_Context") ||
1132
         EQUAL(psChild->pszValue, "ViewContext"))) {
1133
      psMapContext = psChild;
1134
      break;
1135
    } else {
1136
      psChild = psChild->psNext;
1137
    }
1138
  }
1139
1140
  if (psMapContext == NULL) {
1141
    CPLDestroyXMLNode(psRoot);
1142
    msSetError(MS_MAPCONTEXTERR, "Invalid Map Context File (%s)",
1143
               "msLoadMapContext()", filename);
1144
    return MS_FAILURE;
1145
  }
1146
1147
  /* Fetch document version number */
1148
  pszValue = (char *)CPLGetXMLValue(psMapContext, "version", NULL);
1149
  if (!pszValue) {
1150
    msDebug("msLoadMapContext(): Mandatory data version missing in %s, "
1151
            "assuming 0.1.4.",
1152
            filename);
1153
    pszValue = "0.1.4";
1154
  }
1155
1156
  nVersion = msOWSParseVersionString(pszValue);
1157
1158
  /* Make sure this is a supported version */
1159
  switch (nVersion) {
1160
  case OWS_0_1_2:
1161
  case OWS_0_1_4:
1162
  case OWS_0_1_7:
1163
  case OWS_1_0_0:
1164
  case OWS_1_1_0:
1165
    /* All is good, this is a supported version. */
1166
    break;
1167
  default:
1168
    /* Not a supported version */
1169
    msSetError(MS_MAPCONTEXTERR,
1170
               "This version of Map Context is not supported (%s).",
1171
               "msLoadMapContext()", pszValue);
1172
    CPLDestroyXMLNode(psRoot);
1173
    return MS_FAILURE;
1174
  }
1175
1176
  /* Reformat and save Version in metadata */
1177
  msInsertHashTable(&(map->web.metadata), "wms_context_version",
1178
                    msOWSGetVersionString(nVersion, szVersionBuf));
1179
1180
  if (nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) {
1181
    if (msGetMapContextXMLHashValue(psMapContext, "fid", &(map->web.metadata),
1182
                                    "wms_context_fid") == MS_FAILURE) {
1183
      msDebug("Mandatory data fid missing in %s.", filename);
1184
    }
1185
  }
1186
1187
  /*  */
1188
  /* Load the General bloc */
1189
  /*  */
1190
  psChild = CPLGetXMLNode(psMapContext, "General");
1191
  if (psChild == NULL) {
1192
    CPLDestroyXMLNode(psRoot);
1193
    msSetError(MS_MAPCONTEXTERR,
1194
               "The Map Context document provided (%s) does not contain any "
1195
               "General elements.",
1196
               "msLoadMapContext()", filename);
1197
    return MS_FAILURE;
1198
  }
1199
1200
  if (msLoadMapContextGeneral(map, psChild, psMapContext, nVersion, filename) ==
1201
      MS_FAILURE) {
1202
    CPLDestroyXMLNode(psRoot);
1203
    return MS_FAILURE;
1204
  }
1205
1206
  /*  */
1207
  /* Load the bloc LayerList */
1208
  /*  */
1209
  psLayerList = CPLGetXMLNode(psMapContext, "LayerList");
1210
  if (psLayerList != NULL) {
1211
    for (psLayer = psLayerList->psChild; psLayer != NULL;
1212
         psLayer = psLayer->psNext) {
1213
      if (EQUAL(psLayer->pszValue, "Layer")) {
1214
        if (msLoadMapContextLayer(map, psLayer, nVersion, filename,
1215
                                  unique_layer_names) == MS_FAILURE) {
1216
          CPLDestroyXMLNode(psRoot);
1217
          return MS_FAILURE;
1218
        }
1219
      } /* end Layer parsing */
1220
    }   /* for */
1221
  }
1222
1223
  CPLDestroyXMLNode(psRoot);
1224
1225
  return MS_SUCCESS;
1226
1227
#else
1228
0
  msSetError(MS_MAPCONTEXTERR,
1229
0
             "Not implemented since Map Context is not enabled.",
1230
0
             "msGetMapContext()");
1231
0
  return MS_FAILURE;
1232
0
#endif
1233
0
}
1234
1235
/* msSaveMapContext()
1236
**
1237
** Save a mapfile into the OGC Web Map Context format
1238
**
1239
** Take a map object and a file in arguments
1240
*/
1241
0
int msSaveMapContext(mapObj *map, char *filename) {
1242
#if defined(USE_WMS_LYR)
1243
  FILE *stream;
1244
  char szPath[MS_MAXPATHLEN];
1245
  int nStatus;
1246
1247
  /* open file */
1248
  if (filename != NULL && strlen(filename) > 0) {
1249
    stream = fopen(msBuildPath(szPath, map->mappath, filename), "wb");
1250
    if (!stream) {
1251
      msSetError(MS_IOERR, "(%s)", "msSaveMapContext()", filename);
1252
      return (MS_FAILURE);
1253
    }
1254
  } else {
1255
    msSetError(MS_IOERR, "Filename is undefined.", "msSaveMapContext()");
1256
    return MS_FAILURE;
1257
  }
1258
1259
  nStatus = msWriteMapContext(map, stream);
1260
1261
  fclose(stream);
1262
1263
  return nStatus;
1264
#else
1265
0
  msSetError(MS_MAPCONTEXTERR,
1266
0
             "Not implemented since Map Context is not enabled.",
1267
0
             "msSaveMapContext()");
1268
0
  return MS_FAILURE;
1269
0
#endif
1270
0
}
1271
1272
0
int msWriteMapContext(mapObj *map, FILE *stream) {
1273
#if defined(USE_WMS_LYR)
1274
  const char *version;
1275
  char *pszEPSG;
1276
  char *tabspace = NULL, *pszChar, *pszSLD = NULL, *pszSLD2 = NULL;
1277
  char *pszStyleItem, *pszSLDBody;
1278
  char *pszEncodedVal;
1279
  int i, nValue, nVersion = OWS_VERSION_NOTSET;
1280
  /* Dimension element */
1281
  char *pszDimension;
1282
  const char *pszDimUserValue = NULL, *pszDimUnits = NULL,
1283
             *pszDimDefault = NULL;
1284
  const char *pszDimNearValue = NULL, *pszDimUnitSymbol = NULL;
1285
  const char *pszDimMultiValue = NULL;
1286
  int bDimensionList = 0;
1287
1288
  /* Decide which version we're going to return... */
1289
  version = msLookupHashTable(&(map->web.metadata), "wms_context_version");
1290
  if (version == NULL)
1291
    version = "1.1.0";
1292
1293
  nVersion = msOWSParseVersionString(version);
1294
  if (nVersion == OWS_VERSION_BADFORMAT)
1295
    return MS_FAILURE; /* msSetError() already called. */
1296
1297
  /* Make sure this is a supported version */
1298
  /* Note that we don't write 0.1.2 even if we read it. */
1299
  switch (nVersion) {
1300
  case OWS_0_1_4:
1301
  case OWS_0_1_7:
1302
  case OWS_1_0_0:
1303
  case OWS_1_1_0:
1304
    /* All is good, this is a supported version. */
1305
    break;
1306
  default:
1307
    /* Not a supported version */
1308
    msSetError(MS_MAPCONTEXTERR,
1309
               "This version of Map Context is not supported (%s).",
1310
               "msSaveMapContext()", version);
1311
    return MS_FAILURE;
1312
  }
1313
1314
  /* file header */
1315
  msIO_fprintf(stream,
1316
               "<?xml version='1.0' encoding=\"UTF-8\" standalone=\"no\" ?>\n");
1317
1318
  /* set the WMS_Viewer_Context information */
1319
  pszEncodedVal = msEncodeHTMLEntities(version);
1320
  if (nVersion >= OWS_1_0_0) {
1321
    msIO_fprintf(stream, "<ViewContext version=\"%s\"", pszEncodedVal);
1322
  } else if (nVersion >= OWS_0_1_7) {
1323
    msIO_fprintf(stream, "<View_Context version=\"%s\"", pszEncodedVal);
1324
1325
  } else { /* 0.1.4 */
1326
    msIO_fprintf(stream, "<WMS_Viewer_Context version=\"%s\"", pszEncodedVal);
1327
  }
1328
  msFree(pszEncodedVal);
1329
1330
  if (nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) {
1331
    msOWSPrintEncodeMetadata(stream, &(map->web.metadata), NULL,
1332
                             "wms_context_fid", OWS_NOERR, " fid=\"%s\"", "0");
1333
  }
1334
  if (nVersion >= OWS_1_0_0)
1335
    msOWSPrintEncodeParam(stream, "MAP.NAME", map->name, OWS_NOERR,
1336
                          " id=\"%s\"", NULL);
1337
1338
  msIO_fprintf(stream,
1339
               " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
1340
  msIO_fprintf(stream, " xmlns:ogc=\"http://www.opengis.net/ogc\"");
1341
1342
  if (nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) {
1343
    msIO_fprintf(stream, " xmlns:gml=\"http://www.opengis.net/gml\"");
1344
  }
1345
  if (nVersion >= OWS_1_0_0) {
1346
    msIO_fprintf(stream, " xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
1347
    msIO_fprintf(stream, " xmlns=\"http://www.opengis.net/context\"");
1348
    msIO_fprintf(stream, " xmlns:sld=\"http://www.opengis.net/sld\"");
1349
    pszEncodedVal = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
1350
    if (nVersion >= OWS_1_1_0)
1351
      msIO_fprintf(stream,
1352
                   " xsi:schemaLocation=\"http://www.opengis.net/context "
1353
                   "%s/context/1.1.0/context.xsd\">\n",
1354
                   pszEncodedVal);
1355
    else
1356
      msIO_fprintf(stream,
1357
                   " xsi:schemaLocation=\"http://www.opengis.net/context "
1358
                   "%s/context/1.0.0/context.xsd\">\n",
1359
                   pszEncodedVal);
1360
    msFree(pszEncodedVal);
1361
  } else {
1362
    msIO_fprintf(stream, " xmlns:xlink=\"http://www.w3.org/TR/xlink\"");
1363
1364
    pszEncodedVal = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
1365
    msIO_fprintf(stream, " xsi:noNamespaceSchemaLocation=\"%s/contexts/",
1366
                 pszEncodedVal);
1367
    msFree(pszEncodedVal);
1368
    pszEncodedVal = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
1369
    msIO_fprintf(stream, "%s/context.xsd\">\n", pszEncodedVal);
1370
    msFree(pszEncodedVal);
1371
  }
1372
1373
  /* set the General information */
1374
  msIO_fprintf(stream, "  <General>\n");
1375
1376
  /* Window */
1377
  if (map->width != -1 || map->height != -1)
1378
    msIO_fprintf(stream, "    <Window width=\"%d\" height=\"%d\"/>\n",
1379
                 map->width, map->height);
1380
1381
  /* Bounding box corners and spatial reference system */
1382
  if (tabspace)
1383
    free(tabspace);
1384
  tabspace = msStrdup("    ");
1385
  msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "MO", MS_TRUE,
1386
                   &pszEPSG);
1387
  msIO_fprintf(stream,
1388
               "%s<!-- Bounding box corners and spatial reference system -->\n",
1389
               tabspace);
1390
  if (!pszEPSG || (strcasecmp(pszEPSG, "(null)") == 0))
1391
    msIO_fprintf(stream, "<!-- WARNING: Mandatory data 'projection' was "
1392
                         "missing in this context. -->\n");
1393
1394
  pszEncodedVal = msEncodeHTMLEntities(pszEPSG);
1395
  msIO_fprintf(stream,
1396
               "%s<BoundingBox SRS=\"%s\" minx=\"%f\" miny=\"%f\" maxx=\"%f\" "
1397
               "maxy=\"%f\"/>\n",
1398
               tabspace, pszEncodedVal, map->extent.minx, map->extent.miny,
1399
               map->extent.maxx, map->extent.maxy);
1400
  msFree(pszEncodedVal);
1401
  msFree(pszEPSG);
1402
1403
  /* Title, name */
1404
  if (nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) {
1405
    msOWSPrintEncodeParam(stream, "MAP.NAME", map->name, OWS_NOERR,
1406
                          "    <gml:name>%s</gml:name>\n", NULL);
1407
  } else {
1408
    if (nVersion < OWS_0_1_7)
1409
      msOWSPrintEncodeParam(stream, "MAP.NAME", map->name, OWS_NOERR,
1410
                            "    <Name>%s</Name>\n", NULL);
1411
1412
    msIO_fprintf(stream, "%s<!-- Title of Context -->\n", tabspace);
1413
    msOWSPrintEncodeMetadata(stream, &(map->web.metadata), NULL, "wms_title",
1414
                             OWS_WARN, "    <Title>%s</Title>\n", map->name);
1415
  }
1416
1417
  /* keyword */
1418
  if (nVersion >= OWS_1_0_0) {
1419
    if (msLookupHashTable(&(map->web.metadata), "wms_keywordlist") != NULL) {
1420
      char **papszKeywords;
1421
      int nKeywords, iKey;
1422
1423
      const char *pszValue =
1424
          msLookupHashTable(&(map->web.metadata), "wms_keywordlist");
1425
      papszKeywords = msStringSplit(pszValue, ',', &nKeywords);
1426
      if (nKeywords > 0 && papszKeywords) {
1427
        msIO_fprintf(stream, "    <KeywordList>\n");
1428
        for (iKey = 0; iKey < nKeywords; iKey++) {
1429
          pszEncodedVal = msEncodeHTMLEntities(papszKeywords[iKey]);
1430
          msIO_fprintf(stream, "      <Keyword>%s</Keyword>\n", pszEncodedVal);
1431
          msFree(pszEncodedVal);
1432
        }
1433
        msIO_fprintf(stream, "    </KeywordList>\n");
1434
      }
1435
    }
1436
  } else
1437
    msOWSPrintEncodeMetadataList(stream, &(map->web.metadata), NULL,
1438
                                 "wms_keywordlist", "    <Keywords>\n",
1439
                                 "    </Keywords>\n", "      %s\n", NULL);
1440
1441
  /* abstract */
1442
  if (nVersion >= OWS_0_1_7 && nVersion < OWS_1_0_0) {
1443
    msOWSPrintEncodeMetadata(
1444
        stream, &(map->web.metadata), NULL, "wms_abstract", OWS_NOERR,
1445
        "    <gml:description>%s</gml:description>\n", NULL);
1446
  } else {
1447
    msOWSPrintEncodeMetadata(stream, &(map->web.metadata), NULL, "wms_abstract",
1448
                             OWS_NOERR, "    <Abstract>%s</Abstract>\n", NULL);
1449
  }
1450
1451
  /* LogoURL */
1452
  /* The LogoURL have a width, height, format and an URL */
1453
  msOWSPrintURLType(
1454
      stream, &(map->web.metadata), "MO", "logourl", OWS_NOERR, NULL, "LogoURL",
1455
      NULL, " width=\"%s\"", " height=\"%s\"", " format=\"%s\"",
1456
      "      <OnlineResource xlink:type=\"simple\" xlink:href=\"%s\"/>\n",
1457
      MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, NULL, NULL, NULL, NULL,
1458
      NULL, "    ");
1459
1460
  /* DataURL */
1461
  msOWSPrintEncodeMetadata(
1462
      stream, &(map->web.metadata), NULL, "wms_dataurl", OWS_NOERR,
1463
      "    <DataURL>\n      <OnlineResource xlink:type=\"simple\" "
1464
      "xlink:href=\"%s\"/>\n    </DataURL>\n",
1465
      NULL);
1466
1467
  /* DescriptionURL */
1468
  /* The DescriptionURL have a width, height, format and an URL */
1469
  /* The metadata is structured like this: "width height format url" */
1470
  msOWSPrintURLType(
1471
      stream, &(map->web.metadata), "MO", "descriptionurl", OWS_NOERR, NULL,
1472
      "DescriptionURL", NULL, " width=\"%s\"", " height=\"%s\"",
1473
      " format=\"%s\"",
1474
      "      <OnlineResource xlink:type=\"simple\" xlink:href=\"%s\"/>\n",
1475
      MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, NULL, NULL, NULL, NULL,
1476
      NULL, "    ");
1477
1478
  /* Contact Info */
1479
  msOWSPrintContactInfo(stream, tabspace, OWS_1_1_0, &(map->web.metadata),
1480
                        "MO");
1481
1482
  /* Close General */
1483
  msIO_fprintf(stream, "  </General>\n");
1484
  free(tabspace);
1485
1486
  /* Set the layer list */
1487
  msIO_fprintf(stream, "  <LayerList>\n");
1488
1489
  /* Loop on all layer   */
1490
  for (i = 0; i < map->numlayers; i++) {
1491
    if (GET_LAYER(map, i)->status != MS_DELETE &&
1492
        GET_LAYER(map, i)->connectiontype == MS_WMS) {
1493
      const char *pszValue;
1494
      char *pszValueMod;
1495
      const char *pszCurrent;
1496
      if (GET_LAYER(map, i)->status == MS_OFF)
1497
        nValue = 1;
1498
      else
1499
        nValue = 0;
1500
      msIO_fprintf(stream, "    <Layer queryable=\"%d\" hidden=\"%d\">\n",
1501
                   msIsLayerQueryable(GET_LAYER(map, i)), nValue);
1502
1503
      /*  */
1504
      /* Server definition */
1505
      /*  */
1506
      if (nVersion < OWS_1_0_0)
1507
        msOWSPrintEncodeMetadata(
1508
            stream, &(GET_LAYER(map, i)->metadata), NULL, "wms_server_version",
1509
            OWS_WARN, "      <Server service=\"WMS\" version=\"%s\" ", "1.0.0");
1510
      else
1511
        msOWSPrintEncodeMetadata(
1512
            stream, &(GET_LAYER(map, i)->metadata), NULL, "wms_server_version",
1513
            OWS_WARN, "      <Server service=\"OGC:WMS\" version=\"%s\" ",
1514
            "1.0.0");
1515
1516
      if (msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "MO",
1517
                              "server_title"))
1518
        msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata), NULL,
1519
                                 "wms_server_title", OWS_NOERR,
1520
                                 "title=\"%s\">\n", "");
1521
1522
      else if (GET_LAYER(map, i)->name)
1523
        msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata), NULL,
1524
                                 "wms_title", OWS_NOERR, "title=\"%s\">\n",
1525
                                 GET_LAYER(map, i)->name);
1526
      else {
1527
        msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata), NULL,
1528
                                 "wms_title", OWS_NOERR, "title=\"%s\">\n", "");
1529
      }
1530
1531
      /* Get base url of the online resource to be the default value */
1532
      if (GET_LAYER(map, i)->connection)
1533
        pszValueMod = msStrdup(GET_LAYER(map, i)->connection);
1534
      else
1535
        pszValueMod = msStrdup("");
1536
      pszChar = strchr(pszValueMod, '?');
1537
      if (pszChar)
1538
        pszValueMod[pszChar - pszValueMod] = '\0';
1539
      if (msOWSPrintEncodeMetadata(
1540
              stream, &(GET_LAYER(map, i)->metadata), NULL,
1541
              "wms_onlineresource", OWS_WARN,
1542
              "        <OnlineResource xlink:type=\"simple\" "
1543
              "xlink:href=\"%s\"/>\n",
1544
              pszValueMod) == OWS_WARN)
1545
        msIO_fprintf(stream, "<!-- wms_onlineresource not set, using base URL"
1546
                             " , but probably not what you want -->\n");
1547
      msIO_fprintf(stream, "      </Server>\n");
1548
      if (pszValueMod)
1549
        free(pszValueMod);
1550
1551
      /*  */
1552
      /* Layer information */
1553
      /*  */
1554
      msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata), NULL,
1555
                               "wms_name", OWS_WARN, "      <Name>%s</Name>\n",
1556
                               GET_LAYER(map, i)->name);
1557
      msOWSPrintEncodeMetadata(
1558
          stream, &(GET_LAYER(map, i)->metadata), NULL, "wms_title", OWS_WARN,
1559
          "      <Title>%s</Title>\n", GET_LAYER(map, i)->name);
1560
      msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata), NULL,
1561
                               "wms_abstract", OWS_NOERR,
1562
                               "      <Abstract>%s</Abstract>\n", NULL);
1563
1564
      /* DataURL */
1565
      if (nVersion <= OWS_0_1_4) {
1566
        msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata), NULL,
1567
                                 "wms_dataurl", OWS_NOERR,
1568
                                 "      <DataURL>%s</DataURL>\n", NULL);
1569
      } else {
1570
        /* The DataURL have a width, height, format and an URL */
1571
        /* The metadata will be structured like this:  */
1572
        /* "width height format url" */
1573
        /* Note: in version 0.1.7 the width and height are not included  */
1574
        /* in the Context file, but they are included in the metadata for */
1575
        /* for consistency with the URLType. */
1576
        msOWSPrintURLType(stream, &(GET_LAYER(map, i)->metadata), "MO",
1577
                          "dataurl", OWS_NOERR, NULL, "DataURL", NULL,
1578
                          " width=\"%s\"", " height=\"%s\"", " format=\"%s\"",
1579
                          "        <OnlineResource xlink:type=\"simple\""
1580
                          " xlink:href=\"%s\"/>\n",
1581
                          MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, NULL,
1582
                          NULL, NULL, NULL, NULL, "      ");
1583
      }
1584
1585
      /* MetadataURL */
1586
      /* The MetadataURL have a width, height, format and an URL */
1587
      /* The metadata will be structured like this:  */
1588
      /* "width height format url" */
1589
      msOWSPrintURLType(stream, &(GET_LAYER(map, i)->metadata), "MO",
1590
                        "metadataurl", OWS_NOERR, NULL, "MetadataURL", NULL,
1591
                        " width=\"%s\"", " height=\"%s\"", " format=\"%s\"",
1592
                        "        <OnlineResource xlink:type=\"simple\""
1593
                        " xlink:href=\"%s\"/>\n",
1594
                        MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE, NULL,
1595
                        NULL, NULL, NULL, NULL, "      ");
1596
1597
      /* MinScale && MaxScale */
1598
      if (nVersion >= OWS_1_1_0 && GET_LAYER(map, i)->minscaledenom > 0)
1599
        msIO_fprintf(
1600
            stream,
1601
            "      <sld:MinScaleDenominator>%g</sld:MinScaleDenominator>\n",
1602
            GET_LAYER(map, i)->minscaledenom);
1603
      if (nVersion >= OWS_1_1_0 && GET_LAYER(map, i)->maxscaledenom > 0)
1604
        msIO_fprintf(
1605
            stream,
1606
            "      <sld:MaxScaleDenominator>%g</sld:MaxScaleDenominator>\n",
1607
            GET_LAYER(map, i)->maxscaledenom);
1608
1609
      /* Layer SRS */
1610
      msOWSGetEPSGProj(&(GET_LAYER(map, i)->projection),
1611
                       &(GET_LAYER(map, i)->metadata), "MO", MS_FALSE,
1612
                       &pszEPSG);
1613
      if (pszEPSG && (strcasecmp(pszEPSG, "(null)") != 0)) {
1614
        pszEncodedVal = msEncodeHTMLEntities(pszEPSG);
1615
        msIO_fprintf(stream, "      <SRS>%s</SRS>\n", pszEncodedVal);
1616
        msFree(pszEncodedVal);
1617
      }
1618
      msFree(pszEPSG);
1619
1620
      /* Format */
1621
      if (msLookupHashTable(&(GET_LAYER(map, i)->metadata), "wms_formatlist") ==
1622
              NULL &&
1623
          msLookupHashTable(&(GET_LAYER(map, i)->metadata), "wms_format") ==
1624
              NULL) {
1625
        char *pszURL;
1626
        if (GET_LAYER(map, i)->connection)
1627
          pszURL = msStrdup(GET_LAYER(map, i)->connection);
1628
        else
1629
          pszURL = msStrdup("");
1630
1631
        pszValueMod = strstr(pszURL, "FORMAT=");
1632
        if (pszValueMod) {
1633
          pszValueMod += 7;
1634
          pszChar = strchr(pszValueMod, '&');
1635
          if (pszChar)
1636
            pszValueMod[pszChar - pszValueMod] = '\0';
1637
          if (strcasecmp(pszValueMod, "") != 0) {
1638
            pszEncodedVal = msEncodeHTMLEntities(pszValueMod);
1639
            msIO_fprintf(stream, "      <FormatList>\n");
1640
            msIO_fprintf(stream, "        <Format>%s</Format>\n", pszValueMod);
1641
            msIO_fprintf(stream, "      </FormatList>\n");
1642
            msFree(pszEncodedVal);
1643
          }
1644
        }
1645
        free(pszURL);
1646
      } else {
1647
        char **papszFormats;
1648
        int numFormats, nForm;
1649
1650
        pszValue =
1651
            msLookupHashTable(&(GET_LAYER(map, i)->metadata), "wms_formatlist");
1652
        if (!pszValue)
1653
          pszValue =
1654
              msLookupHashTable(&(GET_LAYER(map, i)->metadata), "wms_format");
1655
        pszCurrent =
1656
            msLookupHashTable(&(GET_LAYER(map, i)->metadata), "wms_format");
1657
1658
        papszFormats = msStringSplit(pszValue, ',', &numFormats);
1659
        if (numFormats > 0 && papszFormats) {
1660
          msIO_fprintf(stream, "      <FormatList>\n");
1661
          for (nForm = 0; nForm < numFormats; nForm++) {
1662
            pszEncodedVal = msEncodeHTMLEntities(papszFormats[nForm]);
1663
            if (pszCurrent &&
1664
                (strcasecmp(papszFormats[nForm], pszCurrent) == 0))
1665
              msIO_fprintf(stream,
1666
                           "        <Format current=\"1\">%s</Format>\n",
1667
                           pszEncodedVal);
1668
            else
1669
              msIO_fprintf(stream, "        <Format>%s</Format>\n",
1670
                           pszEncodedVal);
1671
            msFree(pszEncodedVal);
1672
          }
1673
          msIO_fprintf(stream, "      </FormatList>\n");
1674
        }
1675
        if (papszFormats)
1676
          msFreeCharArray(papszFormats, numFormats);
1677
      }
1678
      /* Style */
1679
      /* First check the stylelist */
1680
      pszValue =
1681
          msLookupHashTable(&(GET_LAYER(map, i)->metadata), "wms_stylelist");
1682
      while (pszValue && *pszValue == ' ')
1683
        pszValue++;
1684
      if (pszValue == NULL || strlen(pszValue) < 1) {
1685
        /* Check if the style is in the connection URL */
1686
        char *pszURL;
1687
        if (GET_LAYER(map, i)->connection)
1688
          pszURL = msStrdup(GET_LAYER(map, i)->connection);
1689
        else
1690
          pszURL = msStrdup("");
1691
1692
        /* Grab the STYLES in the URL */
1693
        pszValueMod = strstr(pszURL, "STYLES=");
1694
        if (pszValueMod) {
1695
          pszValueMod += 7;
1696
          pszChar = strchr(pszValueMod, '&');
1697
          if (pszChar)
1698
            pszValueMod[pszChar - pszValueMod] = '\0';
1699
1700
          /* Check the SLD string from the URL */
1701
          if (GET_LAYER(map, i)->connection)
1702
            pszSLD2 = msStrdup(GET_LAYER(map, i)->connection);
1703
          else
1704
            pszSLD2 = msStrdup("");
1705
          if (pszSLD2) {
1706
            pszSLD = strstr(pszSLD2, "SLD=");
1707
            pszSLDBody = strstr(pszSLD2, "SLD_BODY=");
1708
          } else {
1709
            pszSLD = NULL;
1710
            pszSLDBody = NULL;
1711
          }
1712
          /* Check SLD */
1713
          if (pszSLD) {
1714
            pszChar = strchr(pszSLD, '&');
1715
            if (pszChar)
1716
              pszSLD[pszChar - pszSLD] = '\0';
1717
            pszSLD += 4;
1718
          }
1719
          /* Check SLDBody  */
1720
          if (pszSLDBody) {
1721
            pszChar = strchr(pszSLDBody, '&');
1722
            if (pszChar)
1723
              pszSLDBody[pszChar - pszSLDBody] = '\0';
1724
            pszSLDBody += 9;
1725
          }
1726
          if ((pszValueMod && (strcasecmp(pszValueMod, "") != 0)) ||
1727
              (pszSLD && (strcasecmp(pszSLD, "") != 0)) ||
1728
              (pszSLDBody && (strcasecmp(pszSLDBody, "") != 0))) {
1729
            /* Write Name and Title */
1730
            msIO_fprintf(stream, "      <StyleList>\n");
1731
            msIO_fprintf(stream, "        <Style current=\"1\">\n");
1732
            if (pszValueMod && (strcasecmp(pszValueMod, "") != 0)) {
1733
              pszEncodedVal = msEncodeHTMLEntities(pszValueMod);
1734
              msIO_fprintf(stream, "          <Name>%s</Name>\n",
1735
                           pszEncodedVal);
1736
              msIO_fprintf(stream, "          <Title>%s</Title>\n",
1737
                           pszEncodedVal);
1738
              msFree(pszEncodedVal);
1739
            }
1740
            /* Write the SLD string from the URL */
1741
            if (pszSLD && (strcasecmp(pszSLD, "") != 0)) {
1742
              pszEncodedVal = msEncodeHTMLEntities(pszSLD);
1743
              msIO_fprintf(stream, "          <SLD>\n");
1744
              msIO_fprintf(
1745
                  stream, "            <OnlineResource xlink:type=\"simple\" ");
1746
              msIO_fprintf(stream, "xlink:href=\"%s\"/>", pszEncodedVal);
1747
              msIO_fprintf(stream, "          </SLD>\n");
1748
              free(pszEncodedVal);
1749
            } else if (pszSLDBody && (strcasecmp(pszSLDBody, "") != 0)) {
1750
              msIO_fprintf(stream, "          <SLD>\n");
1751
              msIO_fprintf(stream, "            %s\n", pszSLDBody);
1752
              msIO_fprintf(stream, "          </SLD>\n");
1753
            }
1754
            msIO_fprintf(stream, "        </Style>\n");
1755
            msIO_fprintf(stream, "      </StyleList>\n");
1756
          }
1757
          if (pszSLD2) {
1758
            free(pszSLD2);
1759
            pszSLD2 = NULL;
1760
          }
1761
        }
1762
        free(pszURL);
1763
      } else {
1764
        const char *pszCurrent;
1765
        /* If the style information is not in the connection URL, */
1766
        /* read the metadata. */
1767
        pszValue =
1768
            msLookupHashTable(&(GET_LAYER(map, i)->metadata), "wms_stylelist");
1769
        pszCurrent =
1770
            msLookupHashTable(&(GET_LAYER(map, i)->metadata), "wms_style");
1771
        msIO_fprintf(stream, "      <StyleList>\n");
1772
        /* Loop in each style in the style list */
1773
        while (pszValue != NULL) {
1774
          char *pszStyle = msStrdup(pszValue);
1775
          pszChar = strchr(pszStyle, ',');
1776
          if (pszChar != NULL)
1777
            pszStyle[pszChar - pszStyle] = '\0';
1778
          if (pszStyle[0] == '\0') {
1779
            msFree(pszStyle);
1780
            continue;
1781
          }
1782
1783
          if (pszCurrent && (strcasecmp(pszStyle, pszCurrent) == 0))
1784
            msIO_fprintf(stream, "        <Style current=\"1\">\n");
1785
          else
1786
            msIO_fprintf(stream, "        <Style>\n");
1787
1788
          /* Write SLDURL if it is in the metadata */
1789
          pszStyleItem = (char *)malloc(strlen(pszStyle) + 10 + 10);
1790
          sprintf(pszStyleItem, "wms_style_%s_sld", pszStyle);
1791
          if (msLookupHashTable(&(GET_LAYER(map, i)->metadata), pszStyleItem) !=
1792
              NULL) {
1793
            msIO_fprintf(stream, "          <SLD>\n");
1794
            msOWSPrintEncodeMetadata(
1795
                stream, &(GET_LAYER(map, i)->metadata), NULL, pszStyleItem,
1796
                OWS_NOERR,
1797
                "            <OnlineResource xlink:type=\"simple\" "
1798
                "xlink:href=\"%s\"/>\n",
1799
                NULL);
1800
            msIO_fprintf(stream, "          </SLD>\n");
1801
            free(pszStyleItem);
1802
          } else {
1803
            /* If the URL is not there, check for SLDBody */
1804
            sprintf(pszStyleItem, "wms_style_%s_sld_body", pszStyle);
1805
            if (msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1806
                                  pszStyleItem) != NULL) {
1807
              msIO_fprintf(stream, "          <SLD>\n");
1808
              msOWSPrintMetadata(stream, &(GET_LAYER(map, i)->metadata), NULL,
1809
                                 pszStyleItem, OWS_NOERR, "            %s\n",
1810
                                 NULL);
1811
              msIO_fprintf(stream, "          </SLD>\n");
1812
              free(pszStyleItem);
1813
            } else {
1814
              /* If the SLD is not specified, then write the */
1815
              /* name, Title and LegendURL */
1816
              free(pszStyleItem);
1817
              /* Name */
1818
              pszEncodedVal = msEncodeHTMLEntities(pszStyle);
1819
              msIO_fprintf(stream, "          <Name>%s</Name>\n",
1820
                           pszEncodedVal);
1821
              msFree(pszEncodedVal);
1822
              pszStyleItem = (char *)malloc(strlen(pszStyle) + 10 + 8);
1823
              sprintf(pszStyleItem, "wms_style_%s_title", pszStyle);
1824
              /* Title */
1825
              msOWSPrintEncodeMetadata(stream, &(GET_LAYER(map, i)->metadata),
1826
                                       NULL, pszStyleItem, OWS_NOERR,
1827
                                       "          <Title>%s</Title>\n", NULL);
1828
              free(pszStyleItem);
1829
1830
              /* LegendURL */
1831
              pszStyleItem = (char *)malloc(strlen(pszStyle) + 10 + 20);
1832
              sprintf(pszStyleItem, "style_%s_legendurl", pszStyle);
1833
              msOWSPrintURLType(stream, &(GET_LAYER(map, i)->metadata), "M",
1834
                                pszStyleItem, OWS_NOERR, NULL, "LegendURL",
1835
                                NULL, " width=\"%s\"", " height=\"%s\"",
1836
                                " format=\"%s\"",
1837
                                "            <OnlineResource "
1838
                                "xlink:type=\"simple\""
1839
                                " xlink:href=\"%s\"/>\n          ",
1840
                                MS_FALSE, MS_FALSE, MS_FALSE, MS_FALSE, MS_TRUE,
1841
                                NULL, NULL, NULL, NULL, NULL, "          ");
1842
              free(pszStyleItem);
1843
            }
1844
          }
1845
1846
          msIO_fprintf(stream, "        </Style>\n");
1847
1848
          msFree(pszStyle);
1849
          pszValue = strchr(pszValue, ',');
1850
          if (pszValue)
1851
            pszValue++;
1852
        }
1853
        msIO_fprintf(stream, "      </StyleList>\n");
1854
      }
1855
1856
      /* Dimension element */;
1857
      pszCurrent = NULL;
1858
1859
      pszValue = msLookupHashTable(&(GET_LAYER(map, i)->metadata),
1860
                                   "wms_dimensionlist");
1861
      pszCurrent =
1862
          msLookupHashTable(&(GET_LAYER(map, i)->metadata), "wms_dimension");
1863
      while (pszValue != NULL) {
1864
        /* Extract the dimension name from the list */
1865
        pszDimension = msStrdup(pszValue);
1866
        pszChar = strchr(pszDimension, ',');
1867
        if (pszChar != NULL)
1868
          pszDimension[pszChar - pszDimension] = '\0';
1869
        if (strcasecmp(pszDimension, "") == 0) {
1870
          free(pszDimension);
1871
          pszValue = strchr(pszValue, ',');
1872
          if (pszValue)
1873
            pszValue++;
1874
          continue;
1875
        }
1876
1877
        /* From the dimension list, extract the required dimension */
1878
        msOWSGetDimensionInfo(GET_LAYER(map, i), pszDimension, &pszDimUserValue,
1879
                              &pszDimUnits, &pszDimDefault, &pszDimNearValue,
1880
                              &pszDimUnitSymbol, &pszDimMultiValue);
1881
1882
        if (pszDimUserValue == NULL || pszDimUnits == NULL ||
1883
            pszDimUnitSymbol == NULL) {
1884
          free(pszDimension);
1885
          pszValue = strchr(pszValue, ',');
1886
          if (pszValue)
1887
            pszValue++;
1888
          continue;
1889
        }
1890
1891
        if (!bDimensionList) {
1892
          bDimensionList = 1;
1893
          msIO_fprintf(stream, "      <DimensionList>\n");
1894
        }
1895
1896
        /* name */
1897
        msIO_fprintf(stream, "        <Dimension name=\"%s\"", pszDimension);
1898
        /* units */
1899
        msIO_fprintf(stream, " units=\"%s\"", pszDimUnits);
1900
        /* unitSymbol */
1901
        msIO_fprintf(stream, " unitSymbol=\"%s\"", pszDimUnitSymbol);
1902
        /* userValue */
1903
        msIO_fprintf(stream, " userValue=\"%s\"", pszDimUserValue);
1904
        /* default */
1905
        if (pszDimDefault)
1906
          msIO_fprintf(stream, " default=\"%s\"", pszDimDefault);
1907
        /* multipleValues */
1908
        if (pszDimMultiValue)
1909
          msIO_fprintf(stream, " multipleValues=\"%s\"", pszDimMultiValue);
1910
        /* nearestValue */
1911
        if (pszDimNearValue)
1912
          msIO_fprintf(stream, " nearestValue=\"%s\"", pszDimNearValue);
1913
1914
        if (pszCurrent && strcasecmp(pszDimension, pszCurrent) == 0)
1915
          msIO_fprintf(stream, " current=\"1\"");
1916
1917
        msIO_fprintf(stream, "/>\n");
1918
1919
        free(pszDimension);
1920
        pszValue = strchr(pszValue, ',');
1921
        if (pszValue)
1922
          pszValue++;
1923
      }
1924
1925
      if (bDimensionList) {
1926
        msIO_fprintf(stream, "      </DimensionList>\n");
1927
        bDimensionList = 0;
1928
      }
1929
1930
      msIO_fprintf(stream, "    </Layer>\n");
1931
    }
1932
  }
1933
1934
  /* Close layer list */
1935
  msIO_fprintf(stream, "  </LayerList>\n");
1936
  /* Close Map Context */
1937
1938
  if (nVersion >= OWS_1_0_0) {
1939
    msIO_fprintf(stream, "</ViewContext>\n");
1940
  } else if (nVersion >= OWS_0_1_7) {
1941
    msIO_fprintf(stream, "</View_Context>\n");
1942
  } else { /* 0.1.4 */
1943
    msIO_fprintf(stream, "</WMS_Viewer_Context>\n");
1944
  }
1945
1946
  return MS_SUCCESS;
1947
#else
1948
0
  msSetError(MS_MAPCONTEXTERR,
1949
0
             "Not implemented since Map Context is not enabled.",
1950
0
             "msWriteMapContext()");
1951
0
  return MS_FAILURE;
1952
0
#endif
1953
0
}