/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) */ |