Coverage Report

Created: 2025-06-13 06:18

/src/MapServer/src/mapowscommon.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  OGC OWS Common Implementation for use by MapServer OGC code
6
 *           versions:
7
 *           1.0.0 (OGC Document 05-008c1)
8
 *           1.1.0 (OGC document 06-121r3)
9
 *
10
 * Author:   Tom Kralidis (tomkralidis@gmail.com)
11
 *
12
 ******************************************************************************
13
 * Copyright (c) 2006, Tom Kralidis
14
 *
15
 * Permission is hereby granted, free of charge, to any person obtaining a
16
 * copy of this software and associated documentation files (the "Software"),
17
 * to deal in the Software without restriction, including without limitation
18
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19
 * and/or sell copies of the Software, and to permit persons to whom the
20
 * Software is furnished to do so, subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice shall be included in
23
 * all copies of this Software or works derived from this Software.
24
 *
25
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31
 * DEALINGS IN THE SOFTWARE.
32
 ****************************************************************************/
33
34
#include "mapserver.h"
35
#include "mapows.h"
36
37
#ifdef USE_LIBXML2
38
39
#include <libxml/parser.h>
40
#include <libxml/tree.h>
41
42
#include "mapowscommon.h"
43
#include "maplibxml2.h"
44
45
/**
46
 * msOWSCommonServiceIdentification()
47
 *
48
 * returns an object of ServiceIdentification as per:
49
 *
50
 * 1.0.0 subclause 7.4.3
51
 * 1.1.1 subclause 7.4.4
52
 *
53
 * @param map mapObj used to fetch WEB/METADATA
54
 * @param servicetype the OWS type
55
 * @param supported_versions the supported version(s) of the OWS
56
 *
57
 * @return psRootNode xmlNodePtr of XML construct
58
 *
59
 */
60
61
xmlNodePtr msOWSCommonServiceIdentification(xmlNsPtr psNsOws, mapObj *map,
62
                                            const char *servicetype,
63
                                            const char *supported_versions,
64
                                            const char *namespaces,
65
0
                                            const char *validated_language) {
66
0
  const char *value = NULL;
67
68
0
  xmlNodePtr psRootNode = NULL;
69
0
  xmlNodePtr psNode = NULL;
70
71
0
  if (_validateNamespace(psNsOws) == MS_FAILURE)
72
0
    psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI,
73
0
                       BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
74
75
  /* create element name */
76
0
  psRootNode = xmlNewNode(psNsOws, BAD_CAST "ServiceIdentification");
77
78
  /* add child elements */
79
80
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
81
0
                                          "title", validated_language);
82
83
0
  psNode =
84
0
      xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "Title", BAD_CAST value);
85
86
0
  if (!value) {
87
0
    xmlAddSibling(
88
0
        psNode,
89
0
        xmlNewComment(
90
0
            BAD_CAST
91
0
            "WARNING: Optional metadata \"ows_title\" missing for ows:Title"));
92
0
  }
93
94
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
95
0
                                          "abstract", validated_language);
96
97
0
  psNode =
98
0
      xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "Abstract", BAD_CAST value);
99
100
0
  if (!value) {
101
0
    xmlAddSibling(psNode,
102
0
                  xmlNewComment(BAD_CAST
103
0
                                "WARNING: Optional metadata \"ows_abstract\" "
104
0
                                "was missing for ows:Abstract"));
105
0
  }
106
107
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
108
0
                                          "keywordlist", validated_language);
109
110
0
  if (value) {
111
0
    psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "Keywords", NULL);
112
0
    msLibXml2GenerateList(psNode, psNsOws, "Keyword", value, ',');
113
0
  }
114
115
0
  else {
116
0
    xmlAddSibling(
117
0
        psNode,
118
0
        xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_keywordlist\" "
119
0
                               "was missing for ows:KeywordList"));
120
0
  }
121
122
0
  psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "ServiceType",
123
0
                           BAD_CAST servicetype);
124
125
0
  xmlNewProp(psNode, BAD_CAST "codeSpace", BAD_CAST MS_OWSCOMMON_OGC_CODESPACE);
126
127
0
  msLibXml2GenerateList(psRootNode, psNsOws, "ServiceTypeVersion",
128
0
                        supported_versions, ',');
129
130
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
131
0
                                          "fees", validated_language);
132
133
0
  psNode =
134
0
      xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "Fees", BAD_CAST value);
135
136
0
  if (!value) {
137
0
    xmlAddSibling(psNode,
138
0
                  xmlNewComment(BAD_CAST
139
0
                                "WARNING: Optional metadata \"ows_fees\" was "
140
0
                                "missing for ows:Fees"));
141
0
  }
142
143
0
  value =
144
0
      msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
145
0
                                      "accessconstraints", validated_language);
146
147
0
  psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "AccessConstraints",
148
0
                           BAD_CAST value);
149
150
0
  if (!value) {
151
0
    xmlAddSibling(
152
0
        psNode,
153
0
        xmlNewComment(BAD_CAST
154
0
                      "WARNING: Optional metadata \"ows_accessconstraints\" "
155
0
                      "was missing for ows:AccessConstraints"));
156
0
  }
157
158
0
  return psRootNode;
159
0
}
160
161
/**
162
 * msOWSCommonServiceProvider()
163
 *
164
 * returns an object of ServiceProvider as per:
165
 *
166
 *
167
 * 1.0.0 subclause 7.4.4
168
 * 1.1.0 subclause 7.4.5
169
 *
170
 * @param map mapObj to fetch MAP/WEB/METADATA
171
 *
172
 * @return psRootNode xmlNodePtr pointer of XML construct
173
 *
174
 */
175
176
xmlNodePtr msOWSCommonServiceProvider(xmlNsPtr psNsOws, xmlNsPtr psNsXLink,
177
                                      mapObj *map, const char *namespaces,
178
0
                                      const char *validated_language) {
179
0
  const char *value = NULL;
180
181
0
  xmlNodePtr psNode = NULL;
182
0
  xmlNodePtr psRootNode = NULL;
183
0
  xmlNodePtr psSubNode = NULL;
184
0
  xmlNodePtr psSubSubNode = NULL;
185
0
  xmlNodePtr psSubSubSubNode = NULL;
186
187
0
  if (_validateNamespace(psNsOws) == MS_FAILURE)
188
0
    psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI,
189
0
                       BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
190
191
0
  psRootNode = xmlNewNode(psNsOws, BAD_CAST "ServiceProvider");
192
193
  /* add child elements */
194
195
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
196
0
                                          "contactorganization",
197
0
                                          validated_language);
198
199
0
  psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "ProviderName",
200
0
                           BAD_CAST value);
201
202
0
  if (!value) {
203
0
    xmlAddSibling(
204
0
        psNode,
205
0
        xmlNewComment(BAD_CAST
206
0
                      "WARNING: Mandatory metadata \"ows_contactorganization\" "
207
0
                      "was missing for ows:ProviderName"));
208
0
  }
209
210
0
  psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "ProviderSite", NULL);
211
212
0
  xmlNewNsProp(psNode, psNsXLink, BAD_CAST "type", BAD_CAST "simple");
213
214
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
215
0
                                          "service_onlineresource",
216
0
                                          validated_language);
217
218
0
  xmlNewNsProp(psNode, psNsXLink, BAD_CAST "href", BAD_CAST value);
219
220
0
  if (!value) {
221
0
    xmlAddSibling(
222
0
        psNode, xmlNewComment(
223
0
                    BAD_CAST
224
0
                    "WARNING: Optional metadata \"ows_service_onlineresource\" "
225
0
                    "was missing for ows:ProviderSite/@xlink:href"));
226
0
  }
227
228
0
  psNode =
229
0
      xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "ServiceContact", NULL);
230
231
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
232
0
                                          "contactperson", validated_language);
233
234
0
  psSubNode = xmlNewTextChild(psNode, psNsOws, BAD_CAST "IndividualName",
235
0
                              BAD_CAST value);
236
237
0
  if (!value) {
238
0
    xmlAddSibling(
239
0
        psSubNode,
240
0
        xmlNewComment(BAD_CAST
241
0
                      "WARNING: Optional metadata \"ows_contactperson\" was "
242
0
                      "missing for ows:IndividualName"));
243
0
  }
244
245
0
  value = msOWSLookupMetadataWithLanguage(
246
0
      &(map->web.metadata), namespaces, "contactposition", validated_language);
247
248
0
  psSubNode =
249
0
      xmlNewTextChild(psNode, psNsOws, BAD_CAST "PositionName", BAD_CAST value);
250
251
0
  if (!value) {
252
0
    xmlAddSibling(
253
0
        psSubNode,
254
0
        xmlNewComment(BAD_CAST
255
0
                      "WARNING: Optional metadata \"ows_contactposition\" was "
256
0
                      "missing for ows:PositionName"));
257
0
  }
258
259
0
  psSubNode = xmlNewTextChild(psNode, psNsOws, BAD_CAST "ContactInfo", NULL);
260
261
0
  psSubSubNode = xmlNewTextChild(psSubNode, psNsOws, BAD_CAST "Phone", NULL);
262
263
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
264
0
                                          "contactvoicetelephone",
265
0
                                          validated_language);
266
267
0
  psSubSubSubNode =
268
0
      xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "Voice", BAD_CAST value);
269
270
0
  if (!value) {
271
0
    xmlAddSibling(
272
0
        psSubSubSubNode,
273
0
        xmlNewComment(
274
0
            BAD_CAST "WARNING: Optional metadata \"ows_contactvoicetelephone\" "
275
0
                     "was missing for ows:Voice"));
276
0
  }
277
278
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
279
0
                                          "contactfacsimiletelephone",
280
0
                                          validated_language);
281
282
0
  psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "Facsimile",
283
0
                                    BAD_CAST value);
284
285
0
  if (!value) {
286
0
    xmlAddSibling(
287
0
        psSubSubSubNode,
288
0
        xmlNewComment(
289
0
            BAD_CAST
290
0
            "WARNING: Optional metadata \"ows_contactfacsimiletelephone\" was "
291
0
            "missing for ows:Facsimile"));
292
0
  }
293
294
0
  psSubSubNode = xmlNewTextChild(psSubNode, psNsOws, BAD_CAST "Address", NULL);
295
296
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
297
0
                                          "address", validated_language);
298
299
0
  psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws,
300
0
                                    BAD_CAST "DeliveryPoint", BAD_CAST value);
301
302
0
  if (!value) {
303
0
    xmlAddSibling(
304
0
        psSubSubSubNode,
305
0
        xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_address\" was "
306
0
                               "missing for ows:DeliveryPoint"));
307
0
  }
308
309
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
310
0
                                          "city", validated_language);
311
312
0
  psSubSubSubNode =
313
0
      xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "City", BAD_CAST value);
314
315
0
  if (!value) {
316
0
    xmlAddSibling(psSubSubSubNode,
317
0
                  xmlNewComment(BAD_CAST
318
0
                                "WARNING: Optional metadata \"ows_city\" was "
319
0
                                "missing for ows:City"));
320
0
  }
321
322
0
  value = msOWSLookupMetadataWithLanguage(
323
0
      &(map->web.metadata), namespaces, "stateorprovince", validated_language);
324
325
0
  psSubSubSubNode = xmlNewTextChild(
326
0
      psSubSubNode, psNsOws, BAD_CAST "AdministrativeArea", BAD_CAST value);
327
328
0
  if (!value) {
329
0
    xmlAddSibling(
330
0
        psSubSubSubNode,
331
0
        xmlNewComment(BAD_CAST
332
0
                      "WARNING: Optional metadata \"ows_stateorprovince\" was "
333
0
                      "missing for ows:AdministrativeArea"));
334
0
  }
335
336
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
337
0
                                          "postcode", validated_language);
338
339
0
  psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws,
340
0
                                    BAD_CAST "PostalCode", BAD_CAST value);
341
342
0
  if (!value) {
343
0
    xmlAddSibling(psSubSubSubNode,
344
0
                  xmlNewComment(BAD_CAST
345
0
                                "WARNING: Optional metadata \"ows_postcode\" "
346
0
                                "was missing for ows:PostalCode"));
347
0
  }
348
349
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
350
0
                                          "country", validated_language);
351
352
0
  psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "Country",
353
0
                                    BAD_CAST value);
354
355
0
  if (!value) {
356
0
    xmlAddSibling(
357
0
        psSubSubSubNode,
358
0
        xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_country\" was "
359
0
                               "missing for ows:Country"));
360
0
  }
361
362
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
363
0
                                          "contactelectronicmailaddress",
364
0
                                          validated_language);
365
366
0
  psSubSubSubNode = xmlNewTextChild(
367
0
      psSubSubNode, psNsOws, BAD_CAST "ElectronicMailAddress", BAD_CAST value);
368
369
0
  if (!value) {
370
0
    xmlAddSibling(
371
0
        psSubSubSubNode,
372
0
        xmlNewComment(
373
0
            BAD_CAST
374
0
            "WARNING: Optional metadata \"ows_contactelectronicmailaddress\" "
375
0
            "was missing for ows:ElectronicMailAddress"));
376
0
  }
377
378
0
  psSubSubNode =
379
0
      xmlNewTextChild(psSubNode, psNsOws, BAD_CAST "OnlineResource", NULL);
380
381
0
  xmlNewNsProp(psSubSubNode, psNsXLink, BAD_CAST "type", BAD_CAST "simple");
382
383
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
384
0
                                          "service_onlineresource",
385
0
                                          validated_language);
386
387
0
  xmlNewNsProp(psSubSubNode, psNsXLink, BAD_CAST "href", BAD_CAST value);
388
389
0
  if (!value) {
390
0
    xmlAddSibling(
391
0
        psSubSubNode,
392
0
        xmlNewComment(
393
0
            BAD_CAST
394
0
            "WARNING: Optional metadata \"ows_service_onlineresource\" was "
395
0
            "missing for ows:OnlineResource/@xlink:href"));
396
0
  }
397
398
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
399
0
                                          "hoursofservice", validated_language);
400
401
0
  psSubSubNode = xmlNewTextChild(psSubNode, psNsOws, BAD_CAST "HoursOfService",
402
0
                                 BAD_CAST value);
403
404
0
  if (!value) {
405
0
    xmlAddSibling(
406
0
        psSubSubNode,
407
0
        xmlNewComment(BAD_CAST
408
0
                      "WARNING: Optional metadata \"ows_hoursofservice\" was "
409
0
                      "missing for ows:HoursOfService"));
410
0
  }
411
412
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
413
0
                                          "contactinstructions",
414
0
                                          validated_language);
415
416
0
  psSubSubNode = xmlNewTextChild(
417
0
      psSubNode, psNsOws, BAD_CAST "ContactInstructions", BAD_CAST value);
418
419
0
  if (!value) {
420
0
    xmlAddSibling(
421
0
        psSubSubNode,
422
0
        xmlNewComment(BAD_CAST
423
0
                      "WARNING: Optional metadata \"ows_contactinstructions\" "
424
0
                      "was missing for ows:ContactInstructions"));
425
0
  }
426
427
0
  value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces,
428
0
                                          "role", validated_language);
429
430
0
  psSubNode = xmlNewTextChild(psNode, psNsOws, BAD_CAST "Role", BAD_CAST value);
431
432
0
  if (!value) {
433
0
    xmlAddSibling(psSubNode,
434
0
                  xmlNewComment(BAD_CAST
435
0
                                "WARNING: Optional metadata \"ows_role\" was "
436
0
                                "missing for ows:Role"));
437
0
  }
438
439
0
  return psRootNode;
440
0
}
441
442
/**
443
 * msOWSCommonOperationsMetadata()
444
 *
445
 * returns the root element of OperationsMetadata as per:
446
 *
447
 * 1.0.0 subclause 7.4.5
448
 * 1.1.0 subclause 7.4.6
449
 *
450
 * @return psRootNode xmlNodePtr pointer of XML construct
451
 *
452
 */
453
454
0
xmlNodePtr msOWSCommonOperationsMetadata(xmlNsPtr psNsOws) {
455
0
  xmlNodePtr psRootNode = NULL;
456
457
0
  if (_validateNamespace(psNsOws) == MS_FAILURE)
458
0
    psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI,
459
0
                       BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
460
461
0
  psRootNode = xmlNewNode(psNsOws, BAD_CAST "OperationsMetadata");
462
0
  return psRootNode;
463
0
}
464
465
/**
466
 * msOWSCommonOperationsMetadataOperation()
467
 *
468
 * returns an Operation element of OperationsMetadata as per:
469
 *
470
 * 1.0.0 subclause 7.4.5
471
 * 1.1.0 subclause 7.4.6
472
 *
473
 * @param name name of the Operation
474
 * @param method HTTP method: OWS_METHOD_GET, OWS_METHOD_POST or
475
 * OWS_METHOD_GETPOST)
476
 * @param url online resource URL
477
 *
478
 * @return psRootNode xmlNodePtr pointer of XML construct
479
 */
480
481
xmlNodePtr msOWSCommonOperationsMetadataOperation(xmlNsPtr psNsOws,
482
                                                  xmlNsPtr psXLinkNs,
483
                                                  const char *name, int method,
484
0
                                                  const char *url) {
485
0
  if (_validateNamespace(psNsOws) == MS_FAILURE)
486
0
    psNsOws = xmlNewNs(NULL, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI,
487
0
                       BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
488
489
0
  xmlNodePtr psRootNode = xmlNewNode(psNsOws, BAD_CAST "Operation");
490
491
0
  xmlNewProp(psRootNode, BAD_CAST "name", BAD_CAST name);
492
493
0
  xmlNodePtr psNode = xmlNewChild(psRootNode, psNsOws, BAD_CAST "DCP", NULL);
494
495
0
  xmlNodePtr psSubNode = xmlNewChild(psNode, psNsOws, BAD_CAST "HTTP", NULL);
496
497
0
  if (method == OWS_METHOD_GET || method == OWS_METHOD_GETPOST) {
498
0
    xmlNodePtr psSubSubNode =
499
0
        xmlNewChild(psSubNode, psNsOws, BAD_CAST "Get", NULL);
500
0
    xmlNewNsProp(psSubSubNode, psXLinkNs, BAD_CAST "type", BAD_CAST "simple");
501
0
    xmlNewNsProp(psSubSubNode, psXLinkNs, BAD_CAST "href", BAD_CAST url);
502
0
  }
503
504
0
  if (method == OWS_METHOD_POST || method == OWS_METHOD_GETPOST) {
505
0
    xmlNodePtr psSubSubNode =
506
0
        xmlNewChild(psSubNode, psNsOws, BAD_CAST "Post", NULL);
507
0
    xmlNewNsProp(psSubSubNode, psXLinkNs, BAD_CAST "type", BAD_CAST "simple");
508
0
    xmlNewNsProp(psSubSubNode, psXLinkNs, BAD_CAST "href", BAD_CAST url);
509
0
  }
510
511
0
  return psRootNode;
512
0
}
513
514
/**
515
 * msOWSCommonOperationsMetadataDomainType()
516
 *
517
 * returns a Parameter or Constraint element (which are of type ows:DomainType)
518
 * of OperationsMetadata as per:
519
 *
520
 * 1.0.0 subclause 7.4.5
521
 * 1.1.0 subclause 7.4.6
522
 *
523
 * @param version the integerized x.y.z version of OWS Common to use
524
 * @param elname name of the element (Parameter | Constraint)
525
 * @param name name of the Parameter
526
 * @param values list of values (comma separated list) or NULL if none
527
 *
528
 * @return psRootNode xmlNodePtr pointer of XML construct
529
 *
530
 */
531
532
xmlNodePtr msOWSCommonOperationsMetadataDomainType(int version,
533
                                                   xmlNsPtr psNsOws,
534
                                                   const char *elname,
535
                                                   const char *name,
536
0
                                                   const char *values) {
537
0
  if (_validateNamespace(psNsOws) == MS_FAILURE)
538
0
    psNsOws = xmlNewNs(NULL, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI,
539
0
                       BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
540
541
0
  xmlNodePtr psRootNode = xmlNewNode(psNsOws, BAD_CAST elname);
542
543
0
  xmlNewProp(psRootNode, BAD_CAST "name", BAD_CAST name);
544
545
0
  if (version == OWS_1_0_0) {
546
0
    msLibXml2GenerateList(psRootNode, psNsOws, "Value", values, ',');
547
0
  }
548
0
  if (version == OWS_1_1_0 || version == OWS_2_0_0) {
549
0
    xmlNodePtr psNode =
550
0
        xmlNewChild(psRootNode, psNsOws, BAD_CAST "AllowedValues", NULL);
551
0
    msLibXml2GenerateList(psNode, psNsOws, "Value", values, ',');
552
0
  }
553
554
0
  return psRootNode;
555
0
}
556
557
/**
558
 * msOWSCommonExceptionReport()
559
 *
560
 * returns an object of ExceptionReport as per clause 8
561
 *
562
 * @param ows_version the version of OWS Common to use
563
 * @param schemas_location URL to OGC Schemas Location base
564
 * @param version the version of the calling specification
565
 * @param language ISO3166 code of language
566
 * @param exceptionCode a code from the calling specification's list of
567
 * exceptions, or from OWS Common
568
 * @param locator where the exception was encountered (i.e. "layers" keyword)
569
 * @param ExceptionText the actual error message
570
 *
571
 * @return psRootNode xmlNodePtr pointer of XML construct
572
 *
573
 */
574
575
xmlNodePtr msOWSCommonExceptionReport(xmlNsPtr psNsOws, int ows_version,
576
                                      const char *schemas_location,
577
                                      const char *version, const char *language,
578
                                      const char *exceptionCode,
579
                                      const char *locator,
580
0
                                      const char *ExceptionText) {
581
0
  char *xsi_schemaLocation = NULL;
582
0
  char szVersionBuf[OWS_VERSION_MAXLEN];
583
584
0
  xmlNsPtr psNsXsi = NULL;
585
0
  xmlNodePtr psRootNode = NULL;
586
0
  xmlNodePtr psMainNode = NULL;
587
588
0
  psRootNode = xmlNewNode(psNsOws, BAD_CAST "ExceptionReport");
589
590
0
  psNsXsi = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI,
591
0
                     BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX);
592
593
  /* add attributes to root element */
594
0
  xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST version);
595
596
0
  if (ows_version == OWS_1_0_0) {
597
0
    xmlNewProp(psRootNode, BAD_CAST "language", BAD_CAST language);
598
0
  }
599
0
  if (ows_version == OWS_1_1_0) {
600
0
    xmlNewProp(psRootNode, BAD_CAST "xml:lang", BAD_CAST language);
601
0
  }
602
603
0
  xsi_schemaLocation = msStrdup((char *)psNsOws->href);
604
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
605
0
  xsi_schemaLocation =
606
0
      msStringConcatenate(xsi_schemaLocation, (char *)schemas_location);
607
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/ows/");
608
0
  xsi_schemaLocation = msStringConcatenate(
609
0
      xsi_schemaLocation,
610
0
      (char *)msOWSGetVersionString(ows_version, szVersionBuf));
611
0
  xsi_schemaLocation =
612
0
      msStringConcatenate(xsi_schemaLocation, "/owsExceptionReport.xsd");
613
614
  /* add namespace'd attributes to root element */
615
0
  xmlNewNsProp(psRootNode, psNsXsi, BAD_CAST "schemaLocation",
616
0
               BAD_CAST xsi_schemaLocation);
617
618
  /* add child element */
619
0
  psMainNode = xmlNewChild(psRootNode, NULL, BAD_CAST "Exception", NULL);
620
621
  /* add attributes to child */
622
0
  xmlNewProp(psMainNode, BAD_CAST "exceptionCode", BAD_CAST exceptionCode);
623
624
0
  if (locator != NULL) {
625
0
    xmlNewProp(psMainNode, BAD_CAST "locator", BAD_CAST locator);
626
0
  }
627
628
0
  if (ExceptionText != NULL) {
629
0
    xmlNewTextChild(psMainNode, NULL, BAD_CAST "ExceptionText",
630
0
                    BAD_CAST ExceptionText);
631
0
  }
632
633
0
  free(xsi_schemaLocation);
634
0
  return psRootNode;
635
0
}
636
637
/**
638
 * msOWSCommonBoundingBox()
639
 *
640
 * returns an object of BoundingBox as per subclause 10.2.1
641
 *
642
 * If necessary (ie. an EPSG URN GCS such as 4326) the tuple axes will be
643
 * reoriented to match the EPSG coordinate system expectations.
644
 *
645
 * @param psNsOws OWS namespace object
646
 * @param crs the CRS / EPSG code
647
 * @param dimensions number of dimensions of the coordinates
648
 * @param minx minx
649
 * @param miny miny
650
 * @param maxx maxx
651
 * @param maxy maxy
652
 *
653
 * @return psRootNode xmlNodePtr pointer of XML construct
654
 */
655
656
xmlNodePtr msOWSCommonBoundingBox(xmlNsPtr psNsOws, const char *crs,
657
                                  int dimensions, double minx, double miny,
658
0
                                  double maxx, double maxy) {
659
0
  char LowerCorner[100];
660
0
  char UpperCorner[100];
661
0
  char dim_string[100];
662
0
  xmlNodePtr psRootNode = NULL;
663
664
  /* Do we need to reorient tuple axes? */
665
0
  if (crs && strstr(crs, "imageCRS") == NULL) {
666
0
    projectionObj proj;
667
668
0
    msInitProjection(&proj);
669
0
    if (msLoadProjectionString(&proj, (char *)crs) == 0) {
670
0
      msAxisNormalizePoints(&proj, 1, &minx, &miny);
671
0
      msAxisNormalizePoints(&proj, 1, &maxx, &maxy);
672
0
    }
673
0
    msFreeProjection(&proj);
674
0
  }
675
676
0
  if (_validateNamespace(psNsOws) == MS_FAILURE)
677
0
    psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI,
678
0
                       BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
679
680
  /* create element name */
681
0
  psRootNode = xmlNewNode(psNsOws, BAD_CAST "BoundingBox");
682
683
  /* add attributes to the root element */
684
0
  xmlNewProp(psRootNode, BAD_CAST "crs", BAD_CAST crs);
685
686
0
  snprintf(dim_string, sizeof(dim_string), "%d", dimensions);
687
0
  xmlNewProp(psRootNode, BAD_CAST "dimensions", BAD_CAST dim_string);
688
689
0
  snprintf(LowerCorner, sizeof(LowerCorner), "%.15g %.15g", minx, miny);
690
0
  snprintf(UpperCorner, sizeof(UpperCorner), "%.15g %.15g", maxx, maxy);
691
692
  /* add child elements */
693
0
  xmlNewChild(psRootNode, psNsOws, BAD_CAST "LowerCorner",
694
0
              BAD_CAST LowerCorner);
695
0
  xmlNewChild(psRootNode, psNsOws, BAD_CAST "UpperCorner",
696
0
              BAD_CAST UpperCorner);
697
698
0
  return psRootNode;
699
0
}
700
701
/**
702
 * msOWSCommonWGS84BoundingBox()
703
 *
704
 * returns an object of WGS84BoundingBox as per subclause 10.2.2
705
 *
706
 * @param psNsOws OWS namespace object
707
 * @param dimensions number of dimensions of the coordinates
708
 * @param minx minx
709
 * @param miny miny
710
 * @param maxx maxx
711
 * @param maxy maxy
712
 *
713
 * @return psRootNode xmlNodePtr pointer of XML construct
714
 */
715
716
xmlNodePtr msOWSCommonWGS84BoundingBox(xmlNsPtr psNsOws, int dimensions,
717
                                       double minx, double miny, double maxx,
718
0
                                       double maxy) {
719
0
  char LowerCorner[100];
720
0
  char UpperCorner[100];
721
0
  char dim_string[100];
722
723
0
  xmlNodePtr psRootNode = NULL;
724
725
0
  if (_validateNamespace(psNsOws) == MS_FAILURE)
726
0
    psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI,
727
0
                       BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
728
729
  /* create element name */
730
0
  psRootNode = xmlNewNode(psNsOws, BAD_CAST "WGS84BoundingBox");
731
732
0
  snprintf(dim_string, sizeof(dim_string), "%d", dimensions);
733
0
  xmlNewProp(psRootNode, BAD_CAST "dimensions", BAD_CAST dim_string);
734
735
0
  snprintf(LowerCorner, sizeof(LowerCorner), "%.6f %.6f", minx, miny);
736
0
  snprintf(UpperCorner, sizeof(UpperCorner), "%.6f %.6f", maxx, maxy);
737
738
  /* add child elements */
739
0
  xmlNewChild(psRootNode, psNsOws, BAD_CAST "LowerCorner",
740
0
              BAD_CAST LowerCorner);
741
0
  xmlNewChild(psRootNode, psNsOws, BAD_CAST "UpperCorner",
742
0
              BAD_CAST UpperCorner);
743
744
0
  return psRootNode;
745
0
}
746
747
/**
748
 * _validateNamespace()
749
 *
750
 * validates the namespace passed to this module's functions
751
 *
752
 * @param psNsOws namespace object
753
 *
754
 * @return MS_SUCCESS or MS_FAILURE
755
 *
756
 */
757
758
0
int _validateNamespace(xmlNsPtr psNsOws) {
759
0
  char namespace_prefix[10];
760
0
  snprintf(namespace_prefix, sizeof(namespace_prefix), "%s", psNsOws->prefix);
761
0
  if (strcmp(namespace_prefix, MS_OWSCOMMON_OWS_NAMESPACE_PREFIX) == 0)
762
0
    return MS_SUCCESS;
763
0
  else
764
0
    return MS_FAILURE;
765
0
}
766
767
/*
768
 * Valid an xml string against an XML schema
769
 * Inpired from:
770
 * http://xml.developpez.com/sources/?page=validation#validate_XSD_CppCLI_2
771
 * taken from tinyows.org
772
 */
773
0
int msOWSSchemaValidation(const char *xml_schema, const char *xml) {
774
0
  xmlSchemaPtr schema;
775
0
  xmlSchemaParserCtxtPtr ctxt;
776
0
  xmlSchemaValidCtxtPtr validctxt;
777
0
  int ret;
778
0
  xmlDocPtr doc;
779
780
0
  if (!xml_schema || !xml)
781
0
    return MS_FAILURE;
782
783
0
  xmlInitParser();
784
0
  schema = NULL;
785
0
  ret = -1;
786
787
  /* To valid WFS 2.0 requests, we might need to explicitly import */
788
  /* GML and FES 2.0 */
789
0
  if (strlen(xml_schema) > strlen(MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION) &&
790
0
      strcmp(xml_schema + strlen(xml_schema) -
791
0
                 strlen(MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION),
792
0
             MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION) == 0) {
793
0
    const size_t nLenBaseLocation =
794
0
        strlen(xml_schema) - strlen(MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION);
795
0
    char *pszInMemSchema = NULL;
796
0
    char *pszBaseLocation = (char *)msSmallMalloc(nLenBaseLocation + 1);
797
0
    memcpy(pszBaseLocation, xml_schema, nLenBaseLocation);
798
0
    pszBaseLocation[nLenBaseLocation] = '\0';
799
800
0
    pszInMemSchema = msStringConcatenate(
801
0
        pszInMemSchema,
802
0
        "<schema elementFormDefault=\"qualified\" version=\"1.0.0\" "
803
0
        "xmlns=\"http://www.w3.org/2001/XMLSchema\">\n");
804
805
0
    pszInMemSchema = msStringConcatenate(
806
0
        pszInMemSchema, "<import namespace=\"" MS_OWSCOMMON_WFS_20_NAMESPACE_URI
807
0
                        "\" schemaLocation=\"");
808
0
    pszInMemSchema = msStringConcatenate(pszInMemSchema, xml_schema);
809
0
    pszInMemSchema = msStringConcatenate(pszInMemSchema, "\" />\n");
810
811
0
    if (strstr(xml, MS_OWSCOMMON_FES_20_NAMESPACE_URI) != NULL) {
812
0
      pszInMemSchema = msStringConcatenate(
813
0
          pszInMemSchema,
814
0
          "<import namespace=\"" MS_OWSCOMMON_FES_20_NAMESPACE_URI
815
0
          "\" schemaLocation=\"");
816
0
      pszInMemSchema = msStringConcatenate(pszInMemSchema, pszBaseLocation);
817
0
      pszInMemSchema = msStringConcatenate(
818
0
          pszInMemSchema, MS_OWSCOMMON_FES_20_SCHEMA_LOCATION "\" />\n");
819
0
    }
820
821
0
    if (strstr(xml, MS_OWSCOMMON_GML_32_NAMESPACE_URI) != NULL) {
822
0
      pszInMemSchema = msStringConcatenate(
823
0
          pszInMemSchema,
824
0
          "<import namespace=\"" MS_OWSCOMMON_GML_32_NAMESPACE_URI
825
0
          "\" schemaLocation=\"");
826
0
      pszInMemSchema = msStringConcatenate(pszInMemSchema, pszBaseLocation);
827
0
      pszInMemSchema = msStringConcatenate(
828
0
          pszInMemSchema, MS_OWSCOMMON_GML_321_SCHEMA_LOCATION "\" />\n");
829
830
0
    } else if (strstr(xml, MS_OWSCOMMON_GML_NAMESPACE_URI) != NULL) {
831
0
      if (strstr(xml, MS_OWSCOMMON_GML_212_SCHEMA_LOCATION) != NULL) {
832
0
        pszInMemSchema = msStringConcatenate(
833
0
            pszInMemSchema,
834
0
            "<import namespace=\"" MS_OWSCOMMON_GML_NAMESPACE_URI
835
0
            "\" schemaLocation=\"");
836
0
        pszInMemSchema = msStringConcatenate(pszInMemSchema, pszBaseLocation);
837
0
        pszInMemSchema = msStringConcatenate(
838
0
            pszInMemSchema, MS_OWSCOMMON_GML_212_SCHEMA_LOCATION "\" />\n");
839
0
      } else if (strstr(xml, MS_OWSCOMMON_GML_311_SCHEMA_LOCATION) != NULL) {
840
0
        pszInMemSchema = msStringConcatenate(
841
0
            pszInMemSchema,
842
0
            "<import namespace=\"" MS_OWSCOMMON_GML_NAMESPACE_URI
843
0
            "\" schemaLocation=\"");
844
0
        pszInMemSchema = msStringConcatenate(pszInMemSchema, pszBaseLocation);
845
0
        pszInMemSchema = msStringConcatenate(
846
0
            pszInMemSchema, MS_OWSCOMMON_GML_311_SCHEMA_LOCATION "\" />\n");
847
0
      }
848
0
    }
849
850
0
    pszInMemSchema = msStringConcatenate(pszInMemSchema, "</schema>\n");
851
852
0
    ctxt = xmlSchemaNewMemParserCtxt(pszInMemSchema, strlen(pszInMemSchema));
853
0
    msFree(pszInMemSchema);
854
0
    msFree(pszBaseLocation);
855
0
  } else {
856
    /* Open XML Schema File */
857
0
    ctxt = xmlSchemaNewParserCtxt(xml_schema);
858
0
  }
859
860
  /*
861
  xmlSchemaSetParserErrors(ctxt,
862
                           (xmlSchemaValidityErrorFunc) libxml2_callback,
863
                           (xmlSchemaValidityWarningFunc) libxml2_callback,
864
  stderr);
865
  */
866
867
0
  schema = xmlSchemaParse(ctxt);
868
0
  xmlSchemaFreeParserCtxt(ctxt);
869
870
  /* If XML Schema hasn't been rightly loaded */
871
0
  if (schema == NULL) {
872
0
    xmlCleanupParser();
873
0
    return ret;
874
0
  }
875
876
0
  doc = xmlParseDoc((xmlChar *)xml);
877
878
0
  if (doc != NULL) {
879
    /* Loading XML Schema content */
880
0
    validctxt = xmlSchemaNewValidCtxt(schema);
881
    /*
882
    xmlSchemaSetValidErrors(validctxt,
883
                            (xmlSchemaValidityErrorFunc) libxml2_callback,
884
                            (xmlSchemaValidityWarningFunc) libxml2_callback,
885
    stderr);
886
    */
887
    /* validation */
888
0
    ret = xmlSchemaValidateDoc(validctxt, doc);
889
0
    xmlSchemaFreeValidCtxt(validctxt);
890
0
  }
891
892
0
  xmlSchemaFree(schema);
893
0
  xmlFreeDoc(doc);
894
0
  xmlCleanupParser();
895
896
0
  return ret;
897
0
}
898
899
#endif /* defined(USE_LIBXML2) */
900
901
/**
902
 * msOWSCommonNegotiateVersion()
903
 *
904
 * returns a supported version as per subclause 7.3.2
905
 *
906
 * @param requested_version the version passed by the client
907
 * @param supported_versions an array of supported versions
908
 * @param num_supported_versions size of supported_versions
909
 *
910
 * @return supported version integer, or -1 on error
911
 *
912
 */
913
914
int msOWSCommonNegotiateVersion(int requested_version,
915
                                const int supported_versions[],
916
0
                                int num_supported_versions) {
917
0
  int i;
918
919
  /* if version is not set return error */
920
0
  if (!requested_version)
921
0
    return -1;
922
923
  /* return the first entry that's equal to the requested version */
924
0
  for (i = 0; i < num_supported_versions; i++) {
925
0
    if (supported_versions[i] == requested_version)
926
0
      return supported_versions[i];
927
0
  }
928
929
  /* no match; calling code should throw an exception */
930
0
  return -1;
931
0
}