Coverage Report

Created: 2025-06-13 06:18

/src/MapServer/src/mapwcs11.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  OpenGIS Web Coverage Server (WCS) 1.1.0 Implementation.  This
6
 *           file holds some WCS 1.1.0 specific functions but other parts
7
 *           are still implemented in mapwcs.c.
8
 * Author:   Frank Warmerdam and the MapServer team.
9
 *
10
 ******************************************************************************
11
 * Copyright (c) 2007, Frank Warmerdam
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a
14
 * copy of this software and associated documentation files (the "Software"),
15
 * to deal in the Software without restriction, including without limitation
16
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17
 * and/or sell copies of the Software, and to permit persons to whom the
18
 * Software is furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in
21
 * all copies of this Software or works derived from this Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29
 * DEALINGS IN THE SOFTWARE.
30
 *****************************************************************************/
31
32
#include <assert.h>
33
#include "mapserver.h"
34
#include "maperror.h"
35
#include "mapthread.h"
36
#include "mapows.h"
37
#include "mapwcs.h"
38
#include "mapgdal.h"
39
40
#if defined(USE_WCS_SVR)
41
#include "mapwcs.h"
42
#include "gdal.h"
43
#include "cpl_string.h" /* GDAL string handling */
44
#endif
45
46
#if defined(USE_LIBXML2)
47
#include "maplibxml2.h"
48
#endif
49
50
#include <string>
51
52
#if defined(USE_WCS_SVR) && defined(USE_LIBXML2)
53
/*
54
** msWCSException11()
55
**
56
** Report current MapServer error in XML exception format.
57
** Wrapper function around msOWSCommonExceptionReport. Merely
58
** passes WCS specific info.
59
**
60
*/
61
62
int msWCSException11(mapObj *map, const char *exceptionCode,
63
0
                     const char *locator, const char *version) {
64
0
  int size = 0;
65
0
  char *errorString = NULL;
66
0
  char *schemasLocation = NULL;
67
68
0
  xmlDocPtr psDoc = NULL;
69
0
  xmlNodePtr psRootNode = NULL;
70
0
  xmlNsPtr psNsOws = NULL;
71
0
  xmlChar *buffer = NULL;
72
73
0
  psNsOws =
74
0
      xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/ows/1.1", BAD_CAST "ows");
75
76
0
  errorString = msGetErrorString("\n");
77
0
  schemasLocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
78
79
0
  psDoc = xmlNewDoc(BAD_CAST "1.0");
80
81
0
  psRootNode = msOWSCommonExceptionReport(
82
0
      psNsOws, OWS_1_1_0, schemasLocation, version,
83
0
      msOWSGetLanguage(map, "exception"), exceptionCode, locator, errorString);
84
85
0
  xmlDocSetRootElement(psDoc, psRootNode);
86
87
0
  xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/ows/1.1",
88
0
           BAD_CAST "ows");
89
90
0
  msIO_setHeader("Content-Type", "text/xml; charset=UTF-8");
91
0
  msIO_sendHeaders();
92
93
0
  xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1);
94
95
0
  msIO_printf("%s", buffer);
96
97
  /*free buffer and the document */
98
0
  free(errorString);
99
0
  free(schemasLocation);
100
0
  xmlFree(buffer);
101
0
  xmlFreeDoc(psDoc);
102
0
  xmlFreeNs(psNsOws);
103
104
  /* clear error since we have already reported it */
105
0
  msResetErrorList();
106
107
0
  return MS_FAILURE;
108
0
}
109
110
/************************************************************************/
111
/*                       msWCSGetFormatsList11()                        */
112
/*                                                                      */
113
/*      Fetch back a comma delimited formats list for the past layer    */
114
/*      if one is supplied, otherwise for all formats supported by      */
115
/*      the server.  Formats should be identified by mime type.         */
116
/************************************************************************/
117
118
static char *msWCSGetFormatsList11(mapObj *map, layerObj *layer)
119
120
0
{
121
0
  char *format_list = msStrdup("");
122
0
  char **tokens = NULL, **formats = NULL;
123
0
  int i, numtokens = 0, numformats;
124
0
  char *value;
125
126
0
  msApplyDefaultOutputFormats(map);
127
128
  /* -------------------------------------------------------------------- */
129
  /*      Parse from layer metadata.                                      */
130
  /* -------------------------------------------------------------------- */
131
0
  if (layer != NULL &&
132
0
      (value = msOWSGetEncodeMetadata(&(layer->metadata), "CO", "formats",
133
0
                                      "GTiff")) != NULL) {
134
0
    tokens = msStringSplit(value, ' ', &numtokens);
135
0
    msFree(value);
136
0
  }
137
138
  /* -------------------------------------------------------------------- */
139
  /*      Parse from map.web metadata.                                    */
140
  /* -------------------------------------------------------------------- */
141
0
  else if ((value = msOWSGetEncodeMetadata(&(map->web.metadata), "CO",
142
0
                                           "formats", NULL)) != NULL) {
143
0
    tokens = msStringSplit(value, ' ', &numtokens);
144
0
    msFree(value);
145
0
  }
146
147
  /* -------------------------------------------------------------------- */
148
  /*      Or generate from all configured raster output formats that      */
149
  /*      look plausible.                                                 */
150
  /* -------------------------------------------------------------------- */
151
0
  else {
152
0
    tokens = (char **)calloc(map->numoutputformats, sizeof(char *));
153
0
    for (i = 0; i < map->numoutputformats; i++) {
154
0
      switch (map->outputformatlist[i]->renderer) {
155
        /* seeminly normal raster format */
156
0
      case MS_RENDER_WITH_AGG:
157
0
      case MS_RENDER_WITH_RAWDATA:
158
0
        tokens[numtokens++] = msStrdup(map->outputformatlist[i]->name);
159
0
        break;
160
161
        /* rest of formats aren't really WCS compatible */
162
0
      default:
163
0
        break;
164
0
      }
165
0
    }
166
0
  }
167
168
  /* -------------------------------------------------------------------- */
169
  /*      Convert outputFormatObj names into mime types and remove        */
170
  /*      duplicates.                                                     */
171
  /* -------------------------------------------------------------------- */
172
0
  numformats = 0;
173
0
  formats = (char **)calloc(numtokens, sizeof(char *));
174
175
0
  for (i = 0; i < numtokens; i++) {
176
0
    int format_i, j;
177
0
    const char *mimetype;
178
179
0
    for (format_i = 0; format_i < map->numoutputformats; format_i++) {
180
0
      if (strcasecmp(map->outputformatlist[format_i]->name, tokens[i]) == 0)
181
0
        break;
182
0
    }
183
184
0
    if (format_i == map->numoutputformats) {
185
0
      msDebug("Failed to find outputformat info on format '%s', ignore.\n",
186
0
              tokens[i]);
187
0
      continue;
188
0
    }
189
190
0
    mimetype = map->outputformatlist[format_i]->mimetype;
191
0
    if (mimetype == NULL || strlen(mimetype) == 0) {
192
0
      msDebug("No mimetime for format '%s', ignoring.\n", tokens[i]);
193
0
      continue;
194
0
    }
195
196
0
    for (j = 0; j < numformats; j++) {
197
0
      if (strcasecmp(mimetype, formats[j]) == 0)
198
0
        break;
199
0
    }
200
201
0
    if (j < numformats) {
202
0
      msDebug("Format '%s' ignored since mimetype '%s' duplicates another "
203
0
              "outputFormatObj.\n",
204
0
              tokens[i], mimetype);
205
0
      continue;
206
0
    }
207
208
0
    formats[numformats++] = msStrdup(mimetype);
209
0
  }
210
211
0
  msFreeCharArray(tokens, numtokens);
212
213
  /* -------------------------------------------------------------------- */
214
  /*      Turn mimetype list into comma delimited form for easy use       */
215
  /*      with xml functions.                                             */
216
  /* -------------------------------------------------------------------- */
217
0
  for (i = 0; i < numformats; i++) {
218
0
    if (i > 0) {
219
0
      format_list = msStringConcatenate(format_list, (char *)",");
220
0
    }
221
0
    format_list = msStringConcatenate(format_list, formats[i]);
222
0
  }
223
0
  msFreeCharArray(formats, numformats);
224
225
0
  return format_list;
226
0
}
227
228
/************************************************************************/
229
/*                   msWCS_11_20_PrintMetadataLink()                    */
230
/************************************************************************/
231
232
static void msWCS_11_20_PrintMetadataLink(layerObj *layer,
233
                                          const std::string &radix,
234
                                          xmlDocPtr doc,
235
0
                                          xmlNodePtr psCSummary) {
236
0
  const char *value =
237
0
      msOWSLookupMetadata(&(layer->metadata), "CO", (radix + "_href").c_str());
238
0
  if (value) {
239
0
    xmlNsPtr psOwsNs =
240
0
        xmlSearchNs(doc, xmlDocGetRootElement(doc), BAD_CAST "ows");
241
0
    xmlNodePtr psMetadata =
242
0
        xmlNewChild(psCSummary, psOwsNs, BAD_CAST "Metadata", NULL);
243
0
    xmlNsPtr psXlinkNs =
244
0
        xmlSearchNs(doc, xmlDocGetRootElement(doc), BAD_CAST "xlink");
245
0
    const char *metadatalink_type = msOWSLookupMetadata(
246
0
        &(layer->metadata), "CO", (radix + "_type").c_str());
247
0
    const char *metadatalink_format = msOWSLookupMetadata(
248
0
        &(layer->metadata), "CO", (radix + "_format").c_str());
249
250
0
    xmlNewNsProp(psMetadata, psXlinkNs, BAD_CAST "type", BAD_CAST "simple");
251
0
    xmlNewNsProp(psMetadata, psXlinkNs, BAD_CAST "href", BAD_CAST value);
252
0
    if (metadatalink_type != NULL) {
253
0
      xmlNewProp(psMetadata, BAD_CAST "about", BAD_CAST metadatalink_type);
254
0
    }
255
0
    if (metadatalink_format != NULL) {
256
0
      xmlNewNsProp(psMetadata, psXlinkNs, BAD_CAST "role",
257
0
                   BAD_CAST metadatalink_format);
258
0
    }
259
0
  }
260
0
}
261
262
/************************************************************************/
263
/*                   msWCS_11_20_PrintMetadataLinks()                   */
264
/************************************************************************/
265
266
void msWCS_11_20_PrintMetadataLinks(layerObj *layer, xmlDocPtr doc,
267
0
                                    xmlNodePtr psCSummary) {
268
0
  const char *list =
269
0
      msOWSLookupMetadata(&(layer->metadata), "CO", "metadatalink_list");
270
0
  if (list) {
271
0
    int ntokens = 0;
272
0
    char **tokens = msStringSplit(list, ' ', &ntokens);
273
0
    for (int i = 0; i < ntokens; i++) {
274
0
      std::string key("metadatalink_");
275
0
      key += tokens[i];
276
0
      msWCS_11_20_PrintMetadataLink(layer, key, doc, psCSummary);
277
0
    }
278
0
    msFreeCharArray(tokens, ntokens);
279
0
    return;
280
0
  }
281
282
0
  msWCS_11_20_PrintMetadataLink(layer, "metadatalink", doc, psCSummary);
283
0
}
284
285
/************************************************************************/
286
/*                msWCSGetCapabilities11_CoverageSummary()              */
287
/*                                                                      */
288
/*      Generate a WCS 1.1 CoverageSummary.                             */
289
/************************************************************************/
290
291
static int msWCSGetCapabilities11_CoverageSummary(mapObj *map, xmlDocPtr doc,
292
                                                  xmlNodePtr psContents,
293
                                                  layerObj *layer)
294
295
0
{
296
0
  coverageMetadataObj cm;
297
0
  int status;
298
0
  const char *value;
299
0
  char *owned_value;
300
0
  char *format_list;
301
0
  xmlNodePtr psCSummary;
302
0
  xmlNsPtr psOwsNs = xmlSearchNs(doc, psContents, BAD_CAST "ows");
303
0
  int i = 0;
304
305
0
  status = msWCSGetCoverageMetadata(layer, &cm);
306
0
  if (status != MS_SUCCESS)
307
0
    return MS_FAILURE;
308
309
0
  psCSummary = xmlNewChild(psContents, NULL, BAD_CAST "CoverageSummary", NULL);
310
311
  /* -------------------------------------------------------------------- */
312
  /*      Title (from description)                                        */
313
  /* -------------------------------------------------------------------- */
314
0
  value = msOWSLookupMetadata(&(layer->metadata), "CO", "description");
315
0
  if (value == NULL)
316
0
    value = msOWSLookupMetadata(&(layer->metadata), "CO", "title");
317
0
  if (value == NULL)
318
0
    value = layer->name;
319
0
  xmlNewChild(psCSummary, psOwsNs, BAD_CAST "Title", BAD_CAST value);
320
321
  /* -------------------------------------------------------------------- */
322
  /*      Abstract                                                        */
323
  /* -------------------------------------------------------------------- */
324
0
  value = msOWSLookupMetadata(&(layer->metadata), "CO", "abstract");
325
0
  xmlNewChild(psCSummary, psOwsNs, BAD_CAST "Abstract", BAD_CAST value);
326
327
  /* -------------------------------------------------------------------- */
328
  /*      Keywords                                                        */
329
  /* -------------------------------------------------------------------- */
330
0
  value = msOWSLookupMetadata(&(layer->metadata), "CO", "keywordlist");
331
332
0
  if (value) {
333
0
    xmlNodePtr psNode;
334
335
0
    psNode = xmlNewChild(psCSummary, psOwsNs, BAD_CAST "Keywords", NULL);
336
337
0
    int n = 0;
338
0
    char **tokens = msStringSplit(value, ',', &n);
339
0
    if (tokens && n > 0) {
340
0
      for (i = 0; i < n; i++) {
341
0
        xmlNewChild(psNode, NULL, BAD_CAST "Keyword", BAD_CAST tokens[i]);
342
0
      }
343
0
    }
344
0
    msFreeCharArray(tokens, n);
345
0
  }
346
347
  /* -------------------------------------------------------------------- */
348
  /*      Metadata Link                                                   */
349
  /* -------------------------------------------------------------------- */
350
0
  msWCS_11_20_PrintMetadataLinks(layer, doc, psCSummary);
351
352
  /* -------------------------------------------------------------------- */
353
  /*      WGS84 bounding box.                                             */
354
  /* -------------------------------------------------------------------- */
355
0
  xmlAddChild(psCSummary, msOWSCommonWGS84BoundingBox(
356
0
                              psOwsNs, 2, cm.llextent.minx, cm.llextent.miny,
357
0
                              cm.llextent.maxx, cm.llextent.maxy));
358
359
  /* -------------------------------------------------------------------- */
360
  /*      Supported CRSes.                                                */
361
  /* -------------------------------------------------------------------- */
362
0
  if ((owned_value = msOWSGetProjURN(&(layer->projection), &(layer->metadata),
363
0
                                     "CO", MS_FALSE)) != NULL) {
364
    /* ok */
365
0
  } else if ((owned_value = msOWSGetProjURN(&(layer->map->projection),
366
0
                                            &(layer->map->web.metadata), "CO",
367
0
                                            MS_FALSE)) != NULL) {
368
    /* ok */
369
0
  } else
370
0
    msDebug("mapwcs.c: missing required information, no SRSs defined.\n");
371
372
0
  if (owned_value != NULL && strlen(owned_value) > 0)
373
0
    msLibXml2GenerateList(psCSummary, NULL, "SupportedCRS", owned_value, ' ');
374
375
0
  msFree(owned_value);
376
377
  /* -------------------------------------------------------------------- */
378
  /*      SupportedFormats                                                */
379
  /* -------------------------------------------------------------------- */
380
0
  format_list = msWCSGetFormatsList11(map, layer);
381
382
0
  if (strlen(format_list) > 0)
383
0
    msLibXml2GenerateList(psCSummary, NULL, "SupportedFormat", format_list,
384
0
                          ',');
385
386
0
  msFree(format_list);
387
0
  msWCSFreeCoverageMetadata(&cm);
388
389
  /* -------------------------------------------------------------------- */
390
  /*      Identifier (layer name)                                         */
391
  /* -------------------------------------------------------------------- */
392
0
  xmlNewChild(psCSummary, NULL, BAD_CAST "Identifier", BAD_CAST layer->name);
393
394
0
  return MS_SUCCESS;
395
0
}
396
397
/************************************************************************/
398
/*                       msWCSGetCapabilities11()                       */
399
/************************************************************************/
400
int msWCSGetCapabilities11(mapObj *map, wcsParamsObj *params,
401
0
                           cgiRequestObj *req, owsRequestObj *ows_request) {
402
0
  xmlDocPtr psDoc = NULL; /* document pointer */
403
0
  xmlNodePtr psRootNode, psMainNode, psNode;
404
0
  char *identifier_list = NULL, *format_list = NULL;
405
0
  const char *updatesequence = NULL;
406
0
  xmlNsPtr psOwsNs, psXLinkNs;
407
0
  char *schemaLocation = NULL;
408
0
  char *xsi_schemaLocation = NULL;
409
0
  char *script_url = NULL, *script_url_encoded = NULL;
410
411
0
  xmlChar *buffer = NULL;
412
0
  int size = 0, i;
413
0
  msIOContext *context = NULL;
414
415
0
  int ows_version = OWS_1_1_0;
416
417
  /* -------------------------------------------------------------------- */
418
  /*      Handle updatesequence                                           */
419
  /* -------------------------------------------------------------------- */
420
421
0
  updatesequence =
422
0
      msOWSLookupMetadata(&(map->web.metadata), "CO", "updatesequence");
423
424
0
  if (params->updatesequence != NULL) {
425
0
    i = msOWSNegotiateUpdateSequence(params->updatesequence, updatesequence);
426
0
    if (i == 0) { /* current */
427
0
      msSetError(
428
0
          MS_WCSERR, "UPDATESEQUENCE parameter (%s) is equal to server (%s)",
429
0
          "msWCSGetCapabilities11()", params->updatesequence, updatesequence);
430
0
      return msWCSException11(map, "CurrentUpdateSequence", "updatesequence",
431
0
                              params->version);
432
0
    }
433
0
    if (i > 0) { /* invalid */
434
0
      msSetError(
435
0
          MS_WCSERR, "UPDATESEQUENCE parameter (%s) is higher than server (%s)",
436
0
          "msWCSGetCapabilities11()", params->updatesequence, updatesequence);
437
0
      return msWCSException11(map, "InvalidUpdateSequence", "updatesequence",
438
0
                              params->version);
439
0
    }
440
0
  }
441
442
  /* -------------------------------------------------------------------- */
443
  /*      Build list of layer identifiers available.                      */
444
  /* -------------------------------------------------------------------- */
445
0
  identifier_list = msStrdup("");
446
0
  for (i = 0; i < map->numlayers; i++) {
447
0
    layerObj *layer = map->layers[i];
448
0
    int new_length;
449
450
0
    if (!msWCSIsLayerSupported(layer))
451
0
      continue;
452
453
0
    new_length = strlen(identifier_list) + strlen(layer->name) + 2;
454
0
    identifier_list = (char *)realloc(identifier_list, new_length);
455
456
0
    if (strlen(identifier_list) > 0)
457
0
      strcat(identifier_list, ",");
458
0
    strcat(identifier_list, layer->name);
459
0
  }
460
461
  /* -------------------------------------------------------------------- */
462
  /*      Create document.                                                */
463
  /* -------------------------------------------------------------------- */
464
0
  psDoc = xmlNewDoc(BAD_CAST "1.0");
465
466
0
  psRootNode = xmlNewNode(NULL, BAD_CAST "Capabilities");
467
468
0
  xmlDocSetRootElement(psDoc, psRootNode);
469
470
  /* -------------------------------------------------------------------- */
471
  /*      Name spaces                                                     */
472
  /* -------------------------------------------------------------------- */
473
0
  xmlSetNs(
474
0
      psRootNode,
475
0
      xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/wcs/1.1", NULL));
476
0
  psOwsNs = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_110_NAMESPACE_URI,
477
0
                     BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
478
0
  psXLinkNs =
479
0
      xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI,
480
0
               BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX);
481
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI,
482
0
           BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX);
483
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_URI,
484
0
           BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_PREFIX);
485
486
  /*xmlNewProp(psRootNode, BAD_CAST " */
487
0
  xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST params->version);
488
489
0
  updatesequence =
490
0
      msOWSLookupMetadata(&(map->web.metadata), "CO", "updatesequence");
491
492
0
  if (updatesequence)
493
0
    xmlNewProp(psRootNode, BAD_CAST "updateSequence", BAD_CAST updatesequence);
494
495
0
  schemaLocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
496
0
  xsi_schemaLocation = msStrdup("http://www.opengis.net/wcs/1.1");
497
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
498
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemaLocation);
499
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation,
500
0
                                           "/wcs/1.1/wcsGetCapabilities.xsd ");
501
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation,
502
0
                                           MS_OWSCOMMON_OWS_110_NAMESPACE_URI);
503
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
504
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemaLocation);
505
0
  xsi_schemaLocation =
506
0
      msStringConcatenate(xsi_schemaLocation, "/ows/1.1.0/owsAll.xsd");
507
0
  xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation",
508
0
               BAD_CAST xsi_schemaLocation);
509
0
  msFree(schemaLocation);
510
0
  msFree(xsi_schemaLocation);
511
512
  /* -------------------------------------------------------------------- */
513
  /*      Service metadata.                                               */
514
  /* -------------------------------------------------------------------- */
515
0
  if (params->section == NULL || strstr(params->section, "All") != NULL ||
516
0
      strstr(params->section, "ServiceIdentification") != NULL) {
517
0
    xmlAddChild(psRootNode,
518
0
                msOWSCommonServiceIdentification(
519
0
                    psOwsNs, map, "OGC WCS", "2.0.1,1.1.1,1.0.0", "CO", NULL));
520
0
  }
521
522
  /*service provider*/
523
0
  if (params->section == NULL || strstr(params->section, "All") != NULL ||
524
0
      strstr(params->section, "ServiceProvider") != NULL) {
525
0
    xmlAddChild(psRootNode, msOWSCommonServiceProvider(psOwsNs, psXLinkNs, map,
526
0
                                                       "CO", NULL));
527
0
  }
528
529
  /* -------------------------------------------------------------------- */
530
  /*      Operations metadata.                                            */
531
  /* -------------------------------------------------------------------- */
532
  /*operation metadata */
533
0
  if ((script_url = msOWSGetOnlineResource(map, "CO", "onlineresource", req)) ==
534
0
          NULL ||
535
0
      (script_url_encoded = msEncodeHTMLEntities(script_url)) == NULL) {
536
0
    msSetError(MS_WCSERR, "Server URL not found", "msWCSGetCapabilities11()");
537
0
    return msWCSException11(map, "NoApplicableCode", "mapserv",
538
0
                            params->version);
539
0
  }
540
0
  free(script_url);
541
542
0
  if (params->section == NULL || strstr(params->section, "All") != NULL ||
543
0
      strstr(params->section, "OperationsMetadata") != NULL) {
544
0
    psMainNode =
545
0
        xmlAddChild(psRootNode, msOWSCommonOperationsMetadata(psOwsNs));
546
547
    /* -------------------------------------------------------------------- */
548
    /*      GetCapabilities - add Sections and AcceptVersions?              */
549
    /* -------------------------------------------------------------------- */
550
0
    psNode = msOWSCommonOperationsMetadataOperation(
551
0
        psOwsNs, psXLinkNs, "GetCapabilities", OWS_METHOD_GETPOST,
552
0
        script_url_encoded);
553
554
0
    xmlAddChild(psMainNode, psNode);
555
0
    xmlAddChild(psNode,
556
0
                msOWSCommonOperationsMetadataDomainType(
557
0
                    ows_version, psOwsNs, "Parameter", "service", "WCS"));
558
0
    xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
559
0
                            ows_version, psOwsNs, "Parameter", "version",
560
0
                            (char *)params->version));
561
562
    /* -------------------------------------------------------------------- */
563
    /*      DescribeCoverage                                                */
564
    /* -------------------------------------------------------------------- */
565
0
    if (msOWSRequestIsEnabled(map, NULL, "C", "DescribeCoverage", MS_FALSE)) {
566
0
      psNode = msOWSCommonOperationsMetadataOperation(
567
0
          psOwsNs, psXLinkNs, "DescribeCoverage", OWS_METHOD_GETPOST,
568
0
          script_url_encoded);
569
570
0
      xmlAddChild(psMainNode, psNode);
571
0
      xmlAddChild(psNode,
572
0
                  msOWSCommonOperationsMetadataDomainType(
573
0
                      ows_version, psOwsNs, "Parameter", "service", "WCS"));
574
0
      xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
575
0
                              ows_version, psOwsNs, "Parameter", "version",
576
0
                              (char *)params->version));
577
0
      xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
578
0
                              ows_version, psOwsNs, "Parameter", "identifiers",
579
0
                              identifier_list));
580
0
    }
581
582
    /* -------------------------------------------------------------------- */
583
    /*      GetCoverage                                                     */
584
    /* -------------------------------------------------------------------- */
585
0
    if (msOWSRequestIsEnabled(map, NULL, "C", "GetCoverage", MS_FALSE)) {
586
587
0
      psNode = msOWSCommonOperationsMetadataOperation(
588
0
          psOwsNs, psXLinkNs, "GetCoverage", OWS_METHOD_GETPOST,
589
0
          script_url_encoded);
590
591
0
      format_list = msWCSGetFormatsList11(map, NULL);
592
593
0
      xmlAddChild(psMainNode, psNode);
594
0
      xmlAddChild(psNode,
595
0
                  msOWSCommonOperationsMetadataDomainType(
596
0
                      ows_version, psOwsNs, "Parameter", "service", "WCS"));
597
0
      xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
598
0
                              ows_version, psOwsNs, "Parameter", "version",
599
0
                              (char *)params->version));
600
0
      xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
601
0
                              ows_version, psOwsNs, "Parameter", "Identifier",
602
0
                              identifier_list));
603
0
      xmlAddChild(psNode,
604
0
                  msOWSCommonOperationsMetadataDomainType(
605
0
                      ows_version, psOwsNs, "Parameter", "InterpolationType",
606
0
                      "NEAREST_NEIGHBOUR,BILINEAR"));
607
0
      xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
608
0
                              ows_version, psOwsNs, "Parameter", "format",
609
0
                              format_list));
610
0
      xmlAddChild(psNode,
611
0
                  msOWSCommonOperationsMetadataDomainType(
612
0
                      ows_version, psOwsNs, "Parameter", "store", "false"));
613
0
      xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
614
0
                              ows_version, psOwsNs, "Parameter", "GridBaseCRS",
615
0
                              "urn:ogc:def:crs:epsg::4326"));
616
617
0
      msFree(format_list);
618
0
    }
619
0
  }
620
621
  /* -------------------------------------------------------------------- */
622
  /*      Contents section.                                               */
623
  /* -------------------------------------------------------------------- */
624
0
  if (params->section == NULL || strstr(params->section, "All") != NULL ||
625
0
      strstr(params->section, "Contents") != NULL) {
626
0
    psMainNode = xmlNewChild(psRootNode, NULL, BAD_CAST "Contents", NULL);
627
628
0
    if (ows_request->numlayers == 0) {
629
0
      xmlAddChild(psMainNode,
630
0
                  xmlNewComment(BAD_CAST
631
0
                                "WARNING: No WCS layers are enabled. "
632
0
                                "Check wcs/ows_enable_request settings."));
633
0
    } else {
634
0
      for (i = 0; i < map->numlayers; i++) {
635
0
        layerObj *layer = map->layers[i];
636
0
        int status;
637
638
0
        if (!msWCSIsLayerSupported(layer))
639
0
          continue;
640
641
0
        if (!msIntegerInArray(layer->index, ows_request->enabled_layers,
642
0
                              ows_request->numlayers))
643
0
          continue;
644
645
0
        status = msWCSGetCapabilities11_CoverageSummary(map, psDoc, psMainNode,
646
0
                                                        layer);
647
0
        if (status != MS_SUCCESS) {
648
0
          msFree(identifier_list);
649
0
          return MS_FAILURE;
650
0
        }
651
0
      }
652
0
    }
653
0
  }
654
655
  /* -------------------------------------------------------------------- */
656
  /*      Write out the document.                                         */
657
  /* -------------------------------------------------------------------- */
658
659
0
  if (msIO_needBinaryStdout() == MS_FAILURE)
660
0
    return MS_FAILURE;
661
662
0
  msIO_setHeader("Content-Type", "text/xml; charset=UTF-8");
663
0
  msIO_sendHeaders();
664
665
0
  context = msIO_getHandler(stdout);
666
667
0
  xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1);
668
0
  msIO_contextWrite(context, buffer, size);
669
0
  xmlFree(buffer);
670
671
  /*free buffer and the document */
672
  /*xmlFree(buffer);*/
673
0
  xmlFreeDoc(psDoc);
674
675
0
  xmlCleanupParser();
676
677
  /* clean up */
678
0
  free(script_url_encoded);
679
0
  free(identifier_list);
680
681
0
  return (MS_SUCCESS);
682
0
}
683
684
/************************************************************************/
685
/*            msWCSDescribeCoverage_CoverageDescription11()             */
686
/************************************************************************/
687
688
static int msWCSDescribeCoverage_CoverageDescription11(layerObj *layer,
689
                                                       wcsParamsObj *params,
690
                                                       xmlNodePtr psRootNode,
691
                                                       xmlNsPtr psOwsNs)
692
693
0
{
694
0
  int status;
695
0
  coverageMetadataObj cm;
696
0
  xmlNodePtr psCD, psDomain, psSD, psGridCRS;
697
0
  const char *value;
698
699
  /* -------------------------------------------------------------------- */
700
  /*      Verify layer is processable.                                    */
701
  /* -------------------------------------------------------------------- */
702
0
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
703
0
    return MS_FAILURE;
704
705
0
  if (!msWCSIsLayerSupported(layer))
706
0
    return MS_SUCCESS;
707
708
  /* -------------------------------------------------------------------- */
709
  /*      Setup coverage metadata.                                        */
710
  /* -------------------------------------------------------------------- */
711
0
  status = msWCSGetCoverageMetadata(layer, &cm);
712
0
  if (status != MS_SUCCESS)
713
0
    return status;
714
715
  /* fill in bands rangeset info, if required.  */
716
0
  msWCSSetDefaultBandsRangeSetInfo(params, &cm, layer);
717
718
  /* -------------------------------------------------------------------- */
719
  /*      Create CoverageDescription node.                                */
720
  /* -------------------------------------------------------------------- */
721
0
  psCD = xmlNewChild(psRootNode, NULL, BAD_CAST "CoverageDescription", NULL);
722
723
  /* -------------------------------------------------------------------- */
724
  /*      Title (from description)                                        */
725
  /* -------------------------------------------------------------------- */
726
0
  value = msOWSLookupMetadata(&(layer->metadata), "CO", "description");
727
0
  if (value == NULL)
728
0
    value = layer->name;
729
0
  xmlNewChild(psCD, psOwsNs, BAD_CAST "Title", BAD_CAST value);
730
731
  /* -------------------------------------------------------------------- */
732
  /*      Abstract                                                        */
733
  /* -------------------------------------------------------------------- */
734
0
  value = msOWSLookupMetadata(&(layer->metadata), "CO", "abstract");
735
0
  xmlNewChild(psCD, psOwsNs, BAD_CAST "Abstract", BAD_CAST value);
736
737
  /* -------------------------------------------------------------------- */
738
  /*      Keywords                                                        */
739
  /* -------------------------------------------------------------------- */
740
0
  value = msOWSLookupMetadata(&(layer->metadata), "CO", "keywordlist");
741
742
0
  if (value)
743
0
    msLibXml2GenerateList(xmlNewChild(psCD, psOwsNs, BAD_CAST "Keywords", NULL),
744
0
                          NULL, "Keyword", value, ',');
745
746
  /* -------------------------------------------------------------------- */
747
  /*      Identifier (layer name)                                         */
748
  /* -------------------------------------------------------------------- */
749
0
  xmlNewChild(psCD, NULL, BAD_CAST "Identifier", BAD_CAST layer->name);
750
751
  /* -------------------------------------------------------------------- */
752
  /*      Domain                                                          */
753
  /* -------------------------------------------------------------------- */
754
0
  psDomain = xmlNewChild(psCD, NULL, BAD_CAST "Domain", NULL);
755
756
  /* -------------------------------------------------------------------- */
757
  /*      SpatialDomain                                                   */
758
  /* -------------------------------------------------------------------- */
759
0
  psSD = xmlNewChild(psDomain, NULL, BAD_CAST "SpatialDomain", NULL);
760
761
  /* -------------------------------------------------------------------- */
762
  /*      imageCRS bounding box.                                          */
763
  /* -------------------------------------------------------------------- */
764
0
  xmlAddChild(psSD,
765
0
              msOWSCommonBoundingBox(psOwsNs, "urn:ogc:def:crs:OGC::imageCRS",
766
0
                                     2, 0, 0, cm.xsize - 1, cm.ysize - 1));
767
768
  /* -------------------------------------------------------------------- */
769
  /*      native CRS bounding box.                                        */
770
  /* -------------------------------------------------------------------- */
771
0
  xmlAddChild(psSD, msOWSCommonBoundingBox(psOwsNs, cm.srs_urn, 2,
772
0
                                           cm.extent.minx, cm.extent.miny,
773
0
                                           cm.extent.maxx, cm.extent.maxy));
774
775
  /* -------------------------------------------------------------------- */
776
  /*      WGS84 bounding box.                                             */
777
  /* -------------------------------------------------------------------- */
778
0
  xmlAddChild(psSD, msOWSCommonWGS84BoundingBox(
779
0
                        psOwsNs, 2, cm.llextent.minx, cm.llextent.miny,
780
0
                        cm.llextent.maxx, cm.llextent.maxy));
781
782
  /* -------------------------------------------------------------------- */
783
  /*      GridCRS                                                         */
784
  /* -------------------------------------------------------------------- */
785
0
  {
786
0
    char format_buf[500];
787
0
    projectionObj proj;
788
0
    double x0 =
789
0
        cm.geotransform[0] + cm.geotransform[1] / 2 + cm.geotransform[2] / 2;
790
0
    double y0 =
791
0
        cm.geotransform[3] + cm.geotransform[4] / 2 + cm.geotransform[5] / 2;
792
0
    double resx = cm.geotransform[1];
793
0
    double resy = cm.geotransform[5];
794
795
0
    msInitProjection(&proj);
796
0
    msProjectionInheritContextFrom(&proj, &(layer->projection));
797
0
    if (msLoadProjectionString(&proj, cm.srs_urn) == 0) {
798
0
      msAxisNormalizePoints(&proj, 1, &x0, &y0);
799
0
      msAxisNormalizePoints(&proj, 1, &resx, &resy);
800
0
    }
801
0
    msFreeProjection(&proj);
802
803
0
    psGridCRS = xmlNewChild(psSD, NULL, BAD_CAST "GridCRS", NULL);
804
805
0
    xmlNewChild(psGridCRS, NULL, BAD_CAST "GridBaseCRS", BAD_CAST cm.srs_urn);
806
0
    xmlNewChild(psGridCRS, NULL, BAD_CAST "GridType",
807
0
                BAD_CAST "urn:ogc:def:method:WCS:1.1:2dSimpleGrid");
808
809
0
    snprintf(format_buf, sizeof(format_buf), "%.15g %.15g", x0, y0);
810
0
    xmlNewChild(psGridCRS, NULL, BAD_CAST "GridOrigin", BAD_CAST format_buf);
811
812
0
    snprintf(format_buf, sizeof(format_buf), "%.15g %.15g", resx, resy);
813
0
    xmlNewChild(psGridCRS, NULL, BAD_CAST "GridOffsets", BAD_CAST format_buf);
814
815
0
    xmlNewChild(psGridCRS, NULL, BAD_CAST "GridCS",
816
0
                BAD_CAST "urn:ogc:def:cs:OGC:0.0:Grid2dSquareCS");
817
0
  }
818
819
#ifdef notdef
820
  /* TemporalDomain */
821
822
  /* TODO: figure out when a temporal domain is valid, for example only tiled
823
   * rasters support time as a domain, plus we need a timeitem */
824
  if (msOWSLookupMetadata(&(layer->metadata), "CO", "timeposition") ||
825
      msOWSLookupMetadata(&(layer->metadata), "CO", "timeperiod")) {
826
    msIO_printf("      <temporalDomain>\n");
827
828
    /* TimePosition (should support a value AUTO, then we could mine positions
829
     * from the timeitem) */
830
    msOWSPrintEncodeMetadataList(
831
        stdout, &(layer->metadata), "CO", "timeposition", NULL, NULL,
832
        "        <gml:timePosition>%s</gml:timePosition>\n", NULL);
833
834
    /* TODO:  add TimePeriod (only one per layer)  */
835
836
    msIO_printf("      </temporalDomain>\n");
837
  }
838
839
  msIO_printf("    </domainSet>\n");
840
#endif
841
842
  /* -------------------------------------------------------------------- */
843
  /*      Range                                                           */
844
  /* -------------------------------------------------------------------- */
845
0
  {
846
0
    xmlNodePtr psField, psInterpMethods, psAxis;
847
0
    char *value;
848
849
0
    psField = xmlNewChild(xmlNewChild(psCD, NULL, BAD_CAST "Range", NULL), NULL,
850
0
                          BAD_CAST "Field", NULL);
851
852
0
    value = msOWSGetEncodeMetadata(&(layer->metadata), "CO", "rangeset_label",
853
0
                                   NULL);
854
0
    if (value)
855
0
      xmlNewChild(psField, psOwsNs, BAD_CAST "Title", BAD_CAST value);
856
0
    msFree(value);
857
858
    /* ows:Abstract? TODO */
859
860
0
    value = msOWSGetEncodeMetadata(&(layer->metadata), "CO", "rangeset_name",
861
0
                                   "raster");
862
0
    xmlNewChild(psField, NULL, BAD_CAST "Identifier", BAD_CAST value);
863
0
    msFree(value);
864
865
0
    xmlNewChild(xmlNewChild(psField, NULL, BAD_CAST "Definition", NULL),
866
0
                psOwsNs, BAD_CAST "AnyValue", NULL);
867
868
    /* NullValue */
869
0
    value = msOWSGetEncodeMetadata(&(layer->metadata), "CO",
870
0
                                   "rangeset_nullvalue", NULL);
871
0
    if (value)
872
0
      xmlNewChild(psField, NULL, BAD_CAST "NullValue", BAD_CAST value);
873
0
    msFree(value);
874
875
    /* InterpolationMethods */
876
0
    psInterpMethods =
877
0
        xmlNewChild(psField, NULL, BAD_CAST "InterpolationMethods", NULL);
878
879
0
    xmlNewChild(psInterpMethods, NULL, BAD_CAST "InterpolationMethod",
880
0
                BAD_CAST "bilinear");
881
0
    xmlNewChild(psInterpMethods, NULL, BAD_CAST "Default",
882
0
                BAD_CAST "nearest neighbor");
883
884
    /* -------------------------------------------------------------------- */
885
    /*      Bands axis.                                                     */
886
    /* -------------------------------------------------------------------- */
887
0
    {
888
0
      xmlNodePtr psKeys;
889
0
      int iBand;
890
891
0
      value = msOWSGetEncodeMetadata(&(layer->metadata), "CO", "bands_name",
892
0
                                     "bands");
893
0
      psAxis = xmlNewChild(psField, NULL, BAD_CAST "Axis", NULL);
894
0
      xmlNewProp(psAxis, BAD_CAST "identifier", BAD_CAST value);
895
0
      msFree(value);
896
897
0
      psKeys = xmlNewChild(psAxis, NULL, BAD_CAST "AvailableKeys", NULL);
898
899
0
      for (iBand = 0; iBand < cm.bandcount; iBand++) {
900
0
        char szBandName[32];
901
902
0
        snprintf(szBandName, sizeof(szBandName), "%d", iBand + 1);
903
0
        xmlNewChild(psKeys, NULL, BAD_CAST "Key", BAD_CAST szBandName);
904
0
      }
905
0
    }
906
0
  }
907
908
  /* -------------------------------------------------------------------- */
909
  /*      SupportedCRS                                                    */
910
  /* -------------------------------------------------------------------- */
911
0
  {
912
0
    char *owned_value;
913
914
0
    if ((owned_value = msOWSGetProjURN(&(layer->projection), &(layer->metadata),
915
0
                                       "CO", MS_FALSE)) != NULL) {
916
      /* ok */
917
0
    } else if ((owned_value = msOWSGetProjURN(&(layer->map->projection),
918
0
                                              &(layer->map->web.metadata), "CO",
919
0
                                              MS_FALSE)) != NULL) {
920
      /* ok */
921
0
    } else
922
0
      msDebug("mapwcs.c: missing required information, no SRSs defined.\n");
923
924
0
    if (owned_value != NULL && strlen(owned_value) > 0)
925
0
      msLibXml2GenerateList(psCD, NULL, "SupportedCRS", owned_value, ' ');
926
927
0
    msFree(owned_value);
928
0
  }
929
930
  /* -------------------------------------------------------------------- */
931
  /*      SupportedFormats                                                */
932
  /* -------------------------------------------------------------------- */
933
0
  {
934
0
    char *format_list;
935
936
0
    format_list = msWCSGetFormatsList11(layer->map, layer);
937
938
0
    if (strlen(format_list) > 0)
939
0
      msLibXml2GenerateList(psCD, NULL, "SupportedFormat", format_list, ',');
940
941
0
    msFree(format_list);
942
0
  }
943
0
  msWCSFreeCoverageMetadata(&cm);
944
945
0
  return MS_SUCCESS;
946
0
}
947
948
/************************************************************************/
949
/*                      msWCSDescribeCoverage11()                       */
950
/************************************************************************/
951
952
int msWCSDescribeCoverage11(mapObj *map, wcsParamsObj *params,
953
0
                            owsRequestObj *ows_request) {
954
0
  xmlDocPtr psDoc = NULL; /* document pointer */
955
0
  xmlNodePtr psRootNode;
956
0
  xmlNsPtr psOwsNs;
957
0
  char *schemaLocation = NULL;
958
0
  char *xsi_schemaLocation = NULL;
959
960
0
  int i, j;
961
962
  /* -------------------------------------------------------------------- */
963
  /*      We will actually get the coverages list as a single item in     */
964
  /*      a string list with that item having the comma delimited         */
965
  /*      coverage names.  Split it up now, and assign back in place      */
966
  /*      of the old coverages list.                                      */
967
  /* -------------------------------------------------------------------- */
968
0
  if (CSLCount(params->coverages) == 1) {
969
0
    char **old_coverages = params->coverages;
970
0
    params->coverages =
971
0
        CSLTokenizeStringComplex(old_coverages[0], ",", FALSE, FALSE);
972
0
    CSLDestroy(old_coverages);
973
0
  }
974
975
  /* -------------------------------------------------------------------- */
976
  /*      Validate that the requested coverages exist as named layers.    */
977
  /* -------------------------------------------------------------------- */
978
0
  if (params->coverages) { /* use the list */
979
0
    for (j = 0; params->coverages[j]; j++) {
980
0
      i = msGetLayerIndex(map, params->coverages[j]);
981
0
      if ((i == -1) || (!msIntegerInArray(GET_LAYER(map, i)->index,
982
0
                                          ows_request->enabled_layers,
983
0
                                          ows_request->numlayers))) {
984
0
        msSetError(MS_WCSERR, "COVERAGE %s cannot be opened / does not exist",
985
0
                   "msWCSDescribeCoverage()", params->coverages[j]);
986
0
        return msWCSException11(map, "CoverageNotDefined", "coverage",
987
0
                                params->version);
988
0
      }
989
0
    }
990
0
  }
991
992
  /* -------------------------------------------------------------------- */
993
  /*      Create document.                                                */
994
  /* -------------------------------------------------------------------- */
995
0
  psDoc = xmlNewDoc(BAD_CAST "1.0");
996
997
0
  psRootNode = xmlNewNode(NULL, BAD_CAST "CoverageDescriptions");
998
999
0
  xmlDocSetRootElement(psDoc, psRootNode);
1000
1001
  /* -------------------------------------------------------------------- */
1002
  /*      Name spaces                                                     */
1003
  /* -------------------------------------------------------------------- */
1004
0
  xmlSetNs(
1005
0
      psRootNode,
1006
0
      xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/wcs/1.1", NULL));
1007
0
  psOwsNs = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_110_NAMESPACE_URI,
1008
0
                     BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
1009
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI,
1010
0
           BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX);
1011
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI,
1012
0
           BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX);
1013
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_URI,
1014
0
           BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_PREFIX);
1015
1016
0
  schemaLocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
1017
0
  xsi_schemaLocation = msStrdup("http://www.opengis.net/wcs/1.1");
1018
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
1019
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemaLocation);
1020
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation,
1021
0
                                           "/wcs/1.1/wcsDescribeCoverage.xsd ");
1022
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation,
1023
0
                                           MS_OWSCOMMON_OWS_110_NAMESPACE_URI);
1024
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
1025
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemaLocation);
1026
0
  xsi_schemaLocation =
1027
0
      msStringConcatenate(xsi_schemaLocation, "/ows/1.1.0/owsAll.xsd");
1028
0
  xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation",
1029
0
               BAD_CAST xsi_schemaLocation);
1030
0
  msFree(schemaLocation);
1031
0
  msFree(xsi_schemaLocation);
1032
1033
  /* -------------------------------------------------------------------- */
1034
  /*      Generate a CoverageDescription for each requested coverage.     */
1035
  /* -------------------------------------------------------------------- */
1036
1037
0
  if (params->coverages) { /* use the list */
1038
0
    for (j = 0; params->coverages[j]; j++) {
1039
0
      i = msGetLayerIndex(map, params->coverages[j]);
1040
0
      msWCSDescribeCoverage_CoverageDescription11((GET_LAYER(map, i)), params,
1041
0
                                                  psRootNode, psOwsNs);
1042
0
    }
1043
0
  } else { /* return all layers */
1044
0
    for (i = 0; i < map->numlayers; i++) {
1045
1046
0
      if (!msIntegerInArray(GET_LAYER(map, i)->index,
1047
0
                            ows_request->enabled_layers,
1048
0
                            ows_request->numlayers))
1049
0
        continue;
1050
1051
0
      msWCSDescribeCoverage_CoverageDescription11((GET_LAYER(map, i)), params,
1052
0
                                                  psRootNode, psOwsNs);
1053
0
    }
1054
0
  }
1055
1056
  /* -------------------------------------------------------------------- */
1057
  /*      Write out the document.                                         */
1058
  /* -------------------------------------------------------------------- */
1059
0
  {
1060
0
    xmlChar *buffer = NULL;
1061
0
    int size = 0;
1062
0
    msIOContext *context = NULL;
1063
1064
0
    if (msIO_needBinaryStdout() == MS_FAILURE)
1065
0
      return MS_FAILURE;
1066
1067
0
    msIO_setHeader("Content-Type", "text/xml; charset=UTF-8");
1068
0
    msIO_sendHeaders();
1069
1070
0
    context = msIO_getHandler(stdout);
1071
1072
0
    xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1);
1073
0
    msIO_contextWrite(context, buffer, size);
1074
0
    xmlFree(buffer);
1075
0
  }
1076
1077
  /* -------------------------------------------------------------------- */
1078
  /*      Cleanup                                                         */
1079
  /* -------------------------------------------------------------------- */
1080
0
  xmlFreeDoc(psDoc);
1081
0
  xmlCleanupParser();
1082
1083
0
  return MS_SUCCESS;
1084
0
}
1085
1086
#endif /* defined(USE_WCS_SVR) && defined(USE_LIBXML2) */
1087
1088
/************************************************************************/
1089
/*                      msWCSGetCoverageBands11()                       */
1090
/*                                                                      */
1091
/*      We expect input to be of the form:                              */
1092
/*      RangeSubset=raster:interpolation[bands[1]].                     */
1093
/*                                                                      */
1094
/*      RangeSet=raster:[bands[1,2]]                                    */
1095
/*       or                                                             */
1096
/*      RangeSet=raster:bilinear                                        */
1097
/*                                                                      */
1098
/*      This function tries to return a bandlist if found, and will     */
1099
/*      also push an INTERPOLATION keyword into the parameters list     */
1100
/*      if found in the RangeSubset.                                    */
1101
/************************************************************************/
1102
1103
#if defined(USE_WCS_SVR)
1104
int msWCSGetCoverageBands11(mapObj *map, cgiRequestObj *request,
1105
                            wcsParamsObj *params, layerObj *lp,
1106
                            char **p_bandlist)
1107
1108
0
{
1109
0
  char *rangesubset, *field_id;
1110
0
  const char *axis_id;
1111
0
  int i;
1112
1113
  /* -------------------------------------------------------------------- */
1114
  /*      Fetch the RangeSubset from the parameters, skip building a      */
1115
  /*      bands list if not found.                                        */
1116
  /* -------------------------------------------------------------------- */
1117
0
  const char *value = msWCSGetRequestParameter(request, "RangeSubset");
1118
0
  if (value == NULL)
1119
0
    return MS_SUCCESS;
1120
1121
0
  rangesubset = msStrdup(value);
1122
1123
  /* -------------------------------------------------------------------- */
1124
  /*      What is the <Field identifier=...> (rangeset_name)?             */
1125
  /* -------------------------------------------------------------------- */
1126
0
  value = msOWSLookupMetadata(&(lp->metadata), "CO", "rangeset_name");
1127
0
  if (value == NULL)
1128
0
    value = "raster";
1129
0
  field_id = msStrdup(value);
1130
1131
  /* -------------------------------------------------------------------- */
1132
  /*      What is the <Axis identifier=...> (bands_name)?                 */
1133
  /* -------------------------------------------------------------------- */
1134
0
  axis_id = msOWSLookupMetadata(&(lp->metadata), "CO", "bands_name");
1135
0
  if (axis_id == NULL)
1136
0
    axis_id = "bands";
1137
1138
  /* -------------------------------------------------------------------- */
1139
  /*      Parse out the field identifier from the request and verify.     */
1140
  /* -------------------------------------------------------------------- */
1141
0
  value = rangesubset + strlen(field_id);
1142
1143
0
  if (strcasecmp(rangesubset, field_id) == 0) {
1144
0
    free(rangesubset);
1145
0
    free(field_id);
1146
0
    return MS_SUCCESS; /* we only got field ... default options */
1147
0
  }
1148
1149
0
  if (strlen(rangesubset) <= strlen(field_id) + 1 ||
1150
0
      strncasecmp(rangesubset, field_id, strlen(field_id)) != 0 ||
1151
0
      (*value != '[' && *value != ':')) {
1152
0
    msSetError(
1153
0
        MS_WCSERR,
1154
0
        "RangeSubset field name malformed, expected '%s', got RangeSubset=%s",
1155
0
        "msWCSGetCoverageBands11()", field_id, rangesubset);
1156
0
    free(rangesubset);
1157
0
    free(field_id);
1158
0
    return msWCSException11(map, "NoApplicableCode", "mapserv",
1159
0
                            params->version);
1160
0
  }
1161
1162
0
  free(field_id);
1163
0
  field_id = NULL;
1164
1165
  /* -------------------------------------------------------------------- */
1166
  /*      Parse out the interpolation, if found.                          */
1167
  /* -------------------------------------------------------------------- */
1168
0
  if (*value == ':') {
1169
0
    assert(params->interpolation == NULL);
1170
0
    params->interpolation = msStrdup(value + 1);
1171
0
    for (i = 0; params->interpolation[i] != '\0'; i++) {
1172
0
      if (params->interpolation[i] == '[') {
1173
0
        params->interpolation[i] = '\0';
1174
0
        break;
1175
0
      }
1176
0
    }
1177
1178
0
    value += strlen(params->interpolation) + 1;
1179
0
  }
1180
1181
  /* -------------------------------------------------------------------- */
1182
  /*      Parse out the axis name, and verify.                            */
1183
  /* -------------------------------------------------------------------- */
1184
0
  if (*value != '[') {
1185
0
    free(rangesubset);
1186
0
    return MS_SUCCESS;
1187
0
  }
1188
1189
0
  value++;
1190
1191
0
  if (strlen(value) <= strlen(axis_id) + 1 ||
1192
0
      strncasecmp(value, axis_id, strlen(axis_id)) != 0 ||
1193
0
      value[strlen(axis_id)] != '[') {
1194
0
    msSetError(
1195
0
        MS_WCSERR,
1196
0
        "RangeSubset axis name malformed, expected '%s', got RangeSubset=%s",
1197
0
        "msWCSGetCoverageBands11()", axis_id, rangesubset);
1198
0
    free(rangesubset);
1199
0
    return msWCSException11(map, "NoApplicableCode", "mapserv",
1200
0
                            params->version);
1201
0
  }
1202
1203
  /* -------------------------------------------------------------------- */
1204
  /*      Parse the band list.  Basically assuming the band list is       */
1205
  /*      everything from here to a close ';'.                            */
1206
  /* -------------------------------------------------------------------- */
1207
0
  value += strlen(axis_id) + 1;
1208
1209
0
  *p_bandlist = msStrdup(value);
1210
1211
0
  for (i = 0; (*p_bandlist)[i] != '\0'; i++) {
1212
0
    if ((*p_bandlist)[i] == '[') {
1213
0
      (*p_bandlist)[i] = '\0';
1214
0
      break;
1215
0
    }
1216
0
  }
1217
0
  free(rangesubset);
1218
0
  return MS_SUCCESS;
1219
0
}
1220
#endif
1221
1222
/************************************************************************/
1223
/*                       msWCSReturnCoverage11()                        */
1224
/*                                                                      */
1225
/*      Return a render image as a coverage to the caller with WCS      */
1226
/*      1.1 "mime" wrapping.                                            */
1227
/************************************************************************/
1228
1229
#if defined(USE_WCS_SVR)
1230
0
int msWCSReturnCoverage11(wcsParamsObj *params, mapObj *map, imageObj *image) {
1231
0
  int status, i;
1232
0
  char *filename = NULL;
1233
0
  char *base_dir = NULL;
1234
0
  const char *fo_filename;
1235
1236
0
  fo_filename = msGetOutputFormatOption(image->format, "FILENAME", NULL);
1237
1238
  /* -------------------------------------------------------------------- */
1239
  /*      Fetch the driver we will be using and check if it supports      */
1240
  /*      VSIL IO.                                                        */
1241
  /* -------------------------------------------------------------------- */
1242
0
  if (EQUALN(image->format->driver, "GDAL/", 5)) {
1243
0
    GDALDriverH hDriver;
1244
0
    const char *pszExtension = image->format->extension;
1245
1246
0
    msAcquireLock(TLOCK_GDAL);
1247
0
    hDriver = GDALGetDriverByName(image->format->driver + 5);
1248
0
    if (hDriver == NULL) {
1249
0
      msReleaseLock(TLOCK_GDAL);
1250
0
      msSetError(MS_MISCERR, "Failed to find %s driver.",
1251
0
                 "msWCSReturnCoverage11()", image->format->driver + 5);
1252
0
      return msWCSException11(map, "NoApplicableCode", "mapserv",
1253
0
                              params->version);
1254
0
    }
1255
1256
0
    if (pszExtension == NULL)
1257
0
      pszExtension = "img.tmp";
1258
1259
0
    if (msGDALDriverSupportsVirtualIOOutput(hDriver)) {
1260
0
      base_dir = msTmpFile(map, map->mappath, "/vsimem/wcsout", NULL);
1261
0
      if (fo_filename)
1262
0
        filename = msStrdup(CPLFormFilename(base_dir, fo_filename, NULL));
1263
0
      else
1264
0
        filename = msStrdup(CPLFormFilename(base_dir, "out", pszExtension));
1265
1266
      /*            CleanVSIDir( "/vsimem/wcsout" ); */
1267
1268
0
      msReleaseLock(TLOCK_GDAL);
1269
0
      status = msSaveImage(map, image, filename);
1270
0
      if (status != MS_SUCCESS) {
1271
0
        msFree(filename);
1272
0
        msSetError(MS_MISCERR, "msSaveImage() failed",
1273
0
                   "msWCSReturnCoverage11()");
1274
0
        return msWCSException11(map, "NoApplicableCode", "mapserv",
1275
0
                                params->version);
1276
0
      }
1277
0
    }
1278
0
    msReleaseLock(TLOCK_GDAL);
1279
0
  }
1280
1281
  /* -------------------------------------------------------------------- */
1282
  /*      Output stock header.                                            */
1283
  /* -------------------------------------------------------------------- */
1284
0
  msIO_setHeader("Content-Type", "multipart/mixed; boundary=wcs");
1285
0
  msIO_sendHeaders();
1286
0
  msIO_printf("\r\n--wcs\r\n"
1287
0
              "Content-Type: text/xml; charset=UTF-8\r\n"
1288
0
              "Content-ID: wcs.xml\r\n\r\n"
1289
0
              "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1290
0
              "<Coverages\n"
1291
0
              "     xmlns=\"http://www.opengis.net/wcs/1.1\"\n"
1292
0
              "     xmlns:ows=\"http://www.opengis.net/ows/1.1\"\n"
1293
0
              "     xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
1294
0
              "     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
1295
0
              "     xsi:schemaLocation=\"http://www.opengis.net/ows/1.1 "
1296
0
              "../owsCoverages.xsd\">\n"
1297
0
              "  <Coverage>\n");
1298
1299
  /* -------------------------------------------------------------------- */
1300
  /*      If we weren't able to write data under /vsimem, then we just    */
1301
  /*      output a single "stock" filename.                               */
1302
  /* -------------------------------------------------------------------- */
1303
0
  if (filename == NULL) {
1304
0
    msOutputFormatResolveFromImage(map, image);
1305
0
    msIO_fprintf(stdout,
1306
0
                 "    <ows:Reference xlink:href=\"cid:coverage/wcs.%s\"/>\n"
1307
0
                 "  </Coverage>\n"
1308
0
                 "</Coverages>\n"
1309
0
                 "\r\n--wcs\r\n"
1310
0
                 "Content-Type: %s\r\n"
1311
0
                 "Content-Description: coverage data\r\n"
1312
0
                 "Content-Transfer-Encoding: binary\r\n"
1313
0
                 "Content-ID: coverage/wcs.%s\r\n"
1314
0
                 "Content-Disposition: INLINE\r\n\r\n",
1315
0
                 MS_IMAGE_EXTENSION(map->outputformat),
1316
0
                 MS_IMAGE_MIME_TYPE(map->outputformat),
1317
0
                 MS_IMAGE_EXTENSION(map->outputformat));
1318
1319
0
    status = msSaveImage(map, image, NULL);
1320
0
    if (status != MS_SUCCESS) {
1321
0
      msSetError(MS_MISCERR, "msSaveImage() failed", "msWCSReturnCoverage11()");
1322
0
      return msWCSException11(map, "NoApplicableCode", "mapserv",
1323
0
                              params->version);
1324
0
    }
1325
1326
0
    msIO_fprintf(stdout, "\r\n--wcs--\r\n");
1327
0
    return MS_SUCCESS;
1328
0
  }
1329
1330
  /* -------------------------------------------------------------------- */
1331
  /*      When potentially listing multiple files, we take great care     */
1332
  /*      to identify the "primary" file and list it first.  In fact      */
1333
  /*      it is the only file listed in the coverages document.           */
1334
  /* -------------------------------------------------------------------- */
1335
0
  {
1336
0
    char **all_files = CPLReadDir(base_dir);
1337
0
    int count = CSLCount(all_files);
1338
1339
0
    if (msIO_needBinaryStdout() == MS_FAILURE)
1340
0
      return MS_FAILURE;
1341
1342
0
    msAcquireLock(TLOCK_GDAL);
1343
0
    for (i = count - 1; i >= 0; i--) {
1344
0
      const char *this_file = all_files[i];
1345
1346
0
      if (EQUAL(this_file, ".") || EQUAL(this_file, "..")) {
1347
0
        all_files = CSLRemoveStrings(all_files, i, 1, NULL);
1348
0
        continue;
1349
0
      }
1350
1351
0
      if (i > 0 && EQUAL(this_file, CPLGetFilename(filename))) {
1352
0
        all_files = CSLRemoveStrings(all_files, i, 1, NULL);
1353
0
        all_files = CSLInsertString(all_files, 0, CPLGetFilename(filename));
1354
0
        i++;
1355
0
      }
1356
0
    }
1357
1358
0
    msIO_fprintf(stdout,
1359
0
                 "    <ows:Reference xlink:href=\"cid:coverage/%s\"/>\n"
1360
0
                 "  </Coverage>\n"
1361
0
                 "</Coverages>\n",
1362
0
                 CPLGetFilename(filename));
1363
1364
    /* -------------------------------------------------------------------- */
1365
    /*      Dump all the files in the memory directory as mime sections.    */
1366
    /* -------------------------------------------------------------------- */
1367
0
    count = CSLCount(all_files);
1368
1369
0
    for (i = 0; i < count; i++) {
1370
0
      const char *mimetype = NULL;
1371
0
      VSILFILE *fp;
1372
0
      unsigned char block[4000];
1373
0
      int bytes_read;
1374
1375
0
      if (i == 0)
1376
0
        mimetype = MS_IMAGE_MIME_TYPE(map->outputformat);
1377
1378
0
      if (mimetype == NULL)
1379
0
        mimetype = "application/octet-stream";
1380
1381
0
      msIO_fprintf(stdout,
1382
0
                   "\r\n--wcs\r\n"
1383
0
                   "Content-Type: %s\r\n"
1384
0
                   "Content-Description: coverage data\r\n"
1385
0
                   "Content-Transfer-Encoding: binary\r\n"
1386
0
                   "Content-ID: coverage/%s\r\n"
1387
0
                   "Content-Disposition: INLINE\r\n\r\n",
1388
0
                   mimetype, all_files[i]);
1389
1390
0
      fp = VSIFOpenL(CPLFormFilename(base_dir, all_files[i], NULL), "rb");
1391
0
      if (fp == NULL) {
1392
0
        msReleaseLock(TLOCK_GDAL);
1393
0
        msSetError(MS_MISCERR, "Failed to open %s for streaming to stdout.",
1394
0
                   "msWCSReturnCoverage11()", all_files[i]);
1395
0
        return MS_FAILURE;
1396
0
      }
1397
1398
0
      while ((bytes_read = VSIFReadL(block, 1, sizeof(block), fp)) > 0)
1399
0
        msIO_fwrite(block, 1, bytes_read, stdout);
1400
1401
0
      VSIFCloseL(fp);
1402
1403
0
      VSIUnlink(CPLFormFilename(base_dir, all_files[i], NULL));
1404
0
    }
1405
1406
0
    msFree(base_dir);
1407
0
    msFree(filename);
1408
0
    CSLDestroy(all_files);
1409
0
    msReleaseLock(TLOCK_GDAL);
1410
1411
0
    msIO_fprintf(stdout, "\r\n--wcs--\r\n");
1412
0
    return MS_SUCCESS;
1413
0
  }
1414
0
}
1415
#endif /* defined(USE_WCS_SVR) && defined(USE_LIBXML2) */
1416
1417
/************************************************************************/
1418
/* ==================================================================== */
1419
/*  If we don't have libxml2 but WCS SVR was selected, then         */
1420
/*      report WCS 1.1 requests as unsupported.                         */
1421
/* ==================================================================== */
1422
/************************************************************************/
1423
1424
#if defined(USE_WCS_SVR) && !defined(USE_LIBXML2)
1425
1426
#include "mapwcs.h"
1427
1428
/* ==================================================================== */
1429
1430
int msWCSDescribeCoverage11(mapObj *map, wcsParamsObj *params,
1431
                            owsRequestObj *ows_request) {
1432
  msSetError(MS_WCSERR,
1433
             "WCS 1.1 request made, but mapserver requires libxml2 for WCS 1.1 "
1434
             "services and this is not configured.",
1435
             "msWCSDescribeCoverage11()");
1436
  return msWCSException11(map, "NoApplicableCode", "mapserv", params->version);
1437
}
1438
1439
/* ==================================================================== */
1440
1441
int msWCSGetCapabilities11(mapObj *map, wcsParamsObj *params,
1442
                           cgiRequestObj *req, owsRequestObj *ows_request) {
1443
  msSetError(MS_WCSERR,
1444
             "WCS 1.1 request made, but mapserver requires libxml2 for WCS 1.1 "
1445
             "services and this is not configured.",
1446
             "msWCSGetCapabilities11()");
1447
1448
  return msWCSException11(map, "NoApplicableCode", "mapserv", params->version);
1449
}
1450
1451
int msWCSException11(mapObj *map, const char *exceptionCode,
1452
                     const char *locator, const char *version) {
1453
  /* fallback to reporting using 1.0 style exceptions. */
1454
  return msWCSException(map, exceptionCode, locator, "1.0.0");
1455
}
1456
1457
#endif /* defined(USE_WCS_SVR) && !defined(USE_LIBXML2) */