/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 | } |