• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MapServer / MapServer / 19469494645

18 Nov 2025 02:23PM UTC coverage: 40.415% (-1.3%) from 41.715%
19469494645

push

github

jmckenna
update for 8.6.0-beta2 release

60832 of 150520 relevant lines covered (40.41%)

24909.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.12
/src/mapgml.c
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  shapeObj to GML output via MapServer queries.
6
 * Author:   Steve Lime and the MapServer team.
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1996-2005 Regents of the University of Minnesota.
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a
12
 * copy of this software and associated documentation files (the "Software"),
13
 * to deal in the Software without restriction, including without limitation
14
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
 * and/or sell copies of the Software, and to permit persons to whom the
16
 * Software is furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies of this Software or works derived from this Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
 * DEALINGS IN THE SOFTWARE.
28
 ****************************************************************************/
29

30
#include "mapserver.h"
31
#include "maperror.h"
32
#include "mapows.h"
33
#include "mapgml.h"
34
#include "maptime.h"
35

36
/* Use only mapgml.c if WMS or WFS is available (with minor exceptions at end)
37
 */
38

39
#if defined(USE_WMS_SVR) || defined(USE_WFS_SVR)
40

41
static int msGMLGeometryLookup(gmlGeometryListObj *geometryList,
42
                               const char *type);
43

44
/*
45
** Functions that write the feature boundary geometry (i.e. a rectObj).
46
*/
47

48
/* GML 2.1.2 */
49
static int gmlWriteBounds_GML2(FILE *stream, rectObj *rect, const char *srsname,
1,822✔
50
                               const char *tab, const char *pszTopPrefix) {
51
  char *srsname_encoded;
52

53
  if (!stream)
1,822✔
54
    return (MS_FAILURE);
55
  if (!rect)
1,822✔
56
    return (MS_FAILURE);
57
  if (!tab)
1,822✔
58
    return (MS_FAILURE);
59

60
  msIO_fprintf(stream, "%s<%s:boundedBy>\n", tab, pszTopPrefix);
1,822✔
61
  if (srsname) {
1,822✔
62
    srsname_encoded = msEncodeHTMLEntities(srsname);
1,822✔
63
    msIO_fprintf(stream, "%s\t<gml:Box srsName=\"%s\">\n", tab,
1,822✔
64
                 srsname_encoded);
65
    msFree(srsname_encoded);
1,822✔
66
  } else
67
    msIO_fprintf(stream, "%s\t<gml:Box>\n", tab);
×
68

69
  msIO_fprintf(stream, "%s\t\t<gml:coordinates>", tab);
1,822✔
70
  msIO_fprintf(stream, "%.6f,%.6f %.6f,%.6f", rect->minx, rect->miny,
1,822✔
71
               rect->maxx, rect->maxy);
72
  msIO_fprintf(stream, "</gml:coordinates>\n");
1,822✔
73
  msIO_fprintf(stream, "%s\t</gml:Box>\n", tab);
1,822✔
74
  msIO_fprintf(stream, "%s</%s:boundedBy>\n", tab, pszTopPrefix);
1,822✔
75

76
  return MS_SUCCESS;
1,822✔
77
}
78

79
/* GML 3.1 or GML 3.2 (MapServer limits GML encoding to the level 0 profile) */
80
static int gmlWriteBounds_GML3(FILE *stream, rectObj *rect, const char *srsname,
1,182✔
81
                               const char *tab, const char *pszTopPrefix) {
82
  char *srsname_encoded;
83

84
  if (!stream)
1,182✔
85
    return (MS_FAILURE);
86
  if (!rect)
1,182✔
87
    return (MS_FAILURE);
88
  if (!tab)
1,182✔
89
    return (MS_FAILURE);
90

91
  msIO_fprintf(stream, "%s<%s:boundedBy>\n", tab, pszTopPrefix);
1,182✔
92
  if (srsname) {
1,182✔
93
    srsname_encoded = msEncodeHTMLEntities(srsname);
1,182✔
94
    msIO_fprintf(stream, "%s\t<gml:Envelope srsName=\"%s\">\n", tab,
1,182✔
95
                 srsname_encoded);
96
    msFree(srsname_encoded);
1,182✔
97
  } else
98
    msIO_fprintf(stream, "%s\t<gml:Envelope>\n", tab);
×
99

100
  msIO_fprintf(stream, "%s\t\t<gml:lowerCorner>%.6f %.6f</gml:lowerCorner>\n",
1,182✔
101
               tab, rect->minx, rect->miny);
102
  msIO_fprintf(stream, "%s\t\t<gml:upperCorner>%.6f %.6f</gml:upperCorner>\n",
1,182✔
103
               tab, rect->maxx, rect->maxy);
104

105
  msIO_fprintf(stream, "%s\t</gml:Envelope>\n", tab);
1,182✔
106
  msIO_fprintf(stream, "%s</%s:boundedBy>\n", tab, pszTopPrefix);
1,182✔
107

108
  return MS_SUCCESS;
1,182✔
109
}
110

111
static void gmlStartGeometryContainer(FILE *stream, const char *name,
2,545✔
112
                                      const char *namespace, const char *tab) {
113
  const char *tag_name = OWS_GML_DEFAULT_GEOMETRY_NAME;
114

115
  if (name)
2,545✔
116
    tag_name = name;
117

118
  if (namespace)
2,545✔
119
    msIO_fprintf(stream, "%s<%s:%s>\n", tab, namespace, tag_name);
2,545✔
120
  else
121
    msIO_fprintf(stream, "%s<%s>\n", tab, tag_name);
×
122
}
2,545✔
123

124
static void gmlEndGeometryContainer(FILE *stream, const char *name,
2,545✔
125
                                    const char *namespace, const char *tab) {
126
  const char *tag_name = OWS_GML_DEFAULT_GEOMETRY_NAME;
127

128
  if (name)
2,545✔
129
    tag_name = name;
130

131
  if (namespace)
2,545✔
132
    msIO_fprintf(stream, "%s</%s:%s>\n", tab, namespace, tag_name);
2,545✔
133
  else
134
    msIO_fprintf(stream, "%s</%s>\n", tab, tag_name);
×
135
}
2,545✔
136

137
/* GML 2.1.2 */
138
static int gmlWriteGeometry_GML2(FILE *stream, gmlGeometryListObj *geometryList,
1,504✔
139
                                 shapeObj *shape, const char *srsname,
140
                                 const char *namespace, const char *tab,
141
                                 int nSRSDimension, int geometry_precision) {
142
  int i, j, k;
143
  int *innerlist, *outerlist = NULL, numouters;
144
  char *srsname_encoded = NULL;
145

146
  int geometry_aggregate_index, geometry_simple_index;
147
  char *geometry_aggregate_name = NULL, *geometry_simple_name = NULL;
148

149
  if (!stream)
1,504✔
150
    return (MS_FAILURE);
151
  if (!shape)
1,504✔
152
    return (MS_FAILURE);
153
  if (!tab)
1,504✔
154
    return (MS_FAILURE);
155
  if (!geometryList)
1,504✔
156
    return (MS_FAILURE);
157

158
  if (shape->numlines <= 0)
1,504✔
159
    return (MS_SUCCESS); /* empty shape, nothing to output */
160

161
  if (srsname)
1,504✔
162
    srsname_encoded = msEncodeHTMLEntities(srsname);
1,504✔
163

164
  /* feature geometry */
165
  switch (shape->type) {
1,504✔
166
  case (MS_SHAPE_POINT):
1,174✔
167
    geometry_simple_index = msGMLGeometryLookup(geometryList, "point");
1,174✔
168
    geometry_aggregate_index = msGMLGeometryLookup(geometryList, "multipoint");
1,174✔
169
    if (geometry_simple_index >= 0)
1,174✔
170
      geometry_simple_name =
1✔
171
          geometryList->geometries[geometry_simple_index].name;
1✔
172
    if (geometry_aggregate_index >= 0)
1,174✔
173
      geometry_aggregate_name =
1✔
174
          geometryList->geometries[geometry_aggregate_index].name;
1✔
175

176
    if ((geometry_simple_index != -1 && shape->line[0].numpoints == 1 &&
1,174✔
177
         shape->numlines == 1) ||
1✔
178
        (geometry_simple_index != -1 && geometry_aggregate_index == -1) ||
1,173✔
179
        (geometryList->numgeometries == 0 && shape->line[0].numpoints == 1 &&
1,173✔
180
         shape->numlines == 1)) { /* write a Point(s) */
1,171✔
181

182
      for (i = 0; i < shape->numlines; i++) {
2,342✔
183
        for (j = 0; j < shape->line[i].numpoints; j++) {
2,342✔
184
          gmlStartGeometryContainer(stream, geometry_simple_name, namespace,
1,171✔
185
                                    tab);
186

187
          /* Point */
188
          if (srsname_encoded)
1,171✔
189
            msIO_fprintf(stream, "%s<gml:Point srsName=\"%s\">\n", tab,
1,171✔
190
                         srsname_encoded);
191
          else
192
            msIO_fprintf(stream, "%s<gml:Point>\n", tab);
×
193

194
          if (nSRSDimension == 3)
1,171✔
195
            msIO_fprintf(
2✔
196
                stream,
197
                "%s  <gml:coordinates>%.*f,%.*f,%.*f</gml:coordinates>\n", tab,
198
                geometry_precision, shape->line[i].point[j].x,
199
                geometry_precision, shape->line[i].point[j].y,
200
                geometry_precision, shape->line[i].point[j].z);
2✔
201
          else
202
            /* fall-through */
203

204
            msIO_fprintf(stream,
1,169✔
205
                         "%s  <gml:coordinates>%.*f,%.*f</gml:coordinates>\n",
206
                         tab, geometry_precision, shape->line[i].point[j].x,
207
                         geometry_precision, shape->line[i].point[j].y);
1,169✔
208

209
          msIO_fprintf(stream, "%s</gml:Point>\n", tab);
1,171✔
210

211
          gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab);
1,171✔
212
        }
213
      }
214
    } else if ((geometry_aggregate_index != -1) ||
3✔
215
               (geometryList->numgeometries == 0)) { /* write a MultiPoint */
216
      gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace,
3✔
217
                                tab);
218

219
      /* MultiPoint */
220
      if (srsname_encoded)
3✔
221
        msIO_fprintf(stream, "%s<gml:MultiPoint srsName=\"%s\">\n", tab,
3✔
222
                     srsname_encoded);
223
      else
224
        msIO_fprintf(stream, "%s<gml:MultiPoint>\n", tab);
×
225

226
      for (i = 0; i < shape->numlines; i++) {
7✔
227
        for (j = 0; j < shape->line[i].numpoints; j++) {
10✔
228
          msIO_fprintf(stream, "%s  <gml:pointMember>\n", tab);
6✔
229
          msIO_fprintf(stream, "%s    <gml:Point>\n", tab);
6✔
230
          if (nSRSDimension == 3)
6✔
231
            msIO_fprintf(
4✔
232
                stream,
233
                "%s      <gml:coordinates>%.*f,%.*f,%.*f</gml:coordinates>\n",
234
                tab, geometry_precision, shape->line[i].point[j].x,
235
                geometry_precision, shape->line[i].point[j].y,
236
                geometry_precision, shape->line[i].point[j].z);
4✔
237
          else
238
            /* fall-through */
239
            msIO_fprintf(
2✔
240
                stream, "%s      <gml:coordinates>%f,%f</gml:coordinates>\n",
241
                tab, shape->line[i].point[j].x, shape->line[i].point[j].y);
2✔
242
          msIO_fprintf(stream, "%s    </gml:Point>\n", tab);
6✔
243
          msIO_fprintf(stream, "%s  </gml:pointMember>\n", tab);
6✔
244
        }
245
      }
246

247
      msIO_fprintf(stream, "%s</gml:MultiPoint>\n", tab);
3✔
248

249
      gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab);
3✔
250
    } else {
251
      msIO_fprintf(stream, "<!-- Warning: Cannot write geometry- no "
×
252
                           "point/multipoint geometry defined. -->\n");
253
    }
254

255
    break;
256
  case (MS_SHAPE_LINE):
12✔
257
    geometry_simple_index = msGMLGeometryLookup(geometryList, "line");
12✔
258
    geometry_aggregate_index = msGMLGeometryLookup(geometryList, "multiline");
12✔
259
    if (geometry_simple_index >= 0)
12✔
260
      geometry_simple_name =
1✔
261
          geometryList->geometries[geometry_simple_index].name;
1✔
262
    if (geometry_aggregate_index >= 0)
12✔
263
      geometry_aggregate_name =
1✔
264
          geometryList->geometries[geometry_aggregate_index].name;
1✔
265

266
    if ((geometry_simple_index != -1 && shape->numlines == 1) ||
12✔
267
        (geometry_simple_index != -1 && geometry_aggregate_index == -1) ||
11✔
268
        (geometryList->numgeometries == 0 &&
11✔
269
         shape->numlines == 1)) { /* write a LineStrings(s) */
10✔
270
      for (i = 0; i < shape->numlines; i++) {
18✔
271
        gmlStartGeometryContainer(stream, geometry_simple_name, namespace, tab);
9✔
272

273
        /* LineString */
274
        if (srsname_encoded)
9✔
275
          msIO_fprintf(stream, "%s<gml:LineString srsName=\"%s\">\n", tab,
9✔
276
                       srsname_encoded);
277
        else
278
          msIO_fprintf(stream, "%s<gml:LineString>\n", tab);
×
279

280
        msIO_fprintf(stream, "%s  <gml:coordinates>", tab);
9✔
281
        for (j = 0; j < shape->line[i].numpoints; j++) {
88✔
282
          if (nSRSDimension == 3)
79✔
283
            msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision,
4✔
284
                         shape->line[i].point[j].x, geometry_precision,
285
                         shape->line[i].point[j].y, geometry_precision,
286
                         shape->line[i].point[j].z);
4✔
287
          else
288
            /* fall-through */
289
            msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision,
75✔
290
                         shape->line[i].point[j].x, geometry_precision,
291
                         shape->line[i].point[j].y);
75✔
292
        }
293
        msIO_fprintf(stream, "</gml:coordinates>\n");
9✔
294

295
        msIO_fprintf(stream, "%s</gml:LineString>\n", tab);
9✔
296

297
        gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab);
9✔
298
      }
299
    } else if (geometry_aggregate_index != -1 ||
3✔
300
               (geometryList->numgeometries == 0)) { /* write a MultiCurve */
301
      gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace,
3✔
302
                                tab);
303

304
      /* MultiLineString */
305
      if (srsname_encoded)
3✔
306
        msIO_fprintf(stream, "%s<gml:MultiLineString srsName=\"%s\">\n", tab,
3✔
307
                     srsname_encoded);
308
      else
309
        msIO_fprintf(stream, "%s<gml:MultiLineString>\n", tab);
×
310

311
      for (j = 0; j < shape->numlines; j++) {
9✔
312
        msIO_fprintf(stream, "%s  <gml:lineStringMember>\n",
6✔
313
                     tab); /* no srsname at this point */
314
        msIO_fprintf(stream, "%s    <gml:LineString>\n",
6✔
315
                     tab); /* no srsname at this point */
316

317
        msIO_fprintf(stream, "%s      <gml:coordinates>", tab);
6✔
318
        for (i = 0; i < shape->line[j].numpoints; i++) {
18✔
319
          if (nSRSDimension == 3)
12✔
320
            msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision,
8✔
321
                         shape->line[j].point[i].x, geometry_precision,
322
                         shape->line[j].point[i].y, geometry_precision,
323
                         shape->line[j].point[i].z);
8✔
324
          else
325
            /* fall-through */
326
            msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision,
4✔
327
                         shape->line[j].point[i].x, geometry_precision,
328
                         shape->line[j].point[i].y);
4✔
329
        }
330
        msIO_fprintf(stream, "</gml:coordinates>\n");
6✔
331
        msIO_fprintf(stream, "%s    </gml:LineString>\n", tab);
6✔
332
        msIO_fprintf(stream, "%s  </gml:lineStringMember>\n", tab);
6✔
333
      }
334

335
      msIO_fprintf(stream, "%s</gml:MultiLineString>\n", tab);
3✔
336

337
      gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab);
3✔
338
    } else {
339
      msIO_fprintf(stream, "<!-- Warning: Cannot write geometry- no "
×
340
                           "line/multiline geometry defined. -->\n");
341
    }
342

343
    break;
344
  case (
318✔
345
      MS_SHAPE_POLYGON): /* this gets nasty, since our shapes are so flexible */
346
    geometry_simple_index = msGMLGeometryLookup(geometryList, "polygon");
318✔
347
    geometry_aggregate_index =
348
        msGMLGeometryLookup(geometryList, "multipolygon");
318✔
349
    if (geometry_simple_index >= 0)
318✔
350
      geometry_simple_name =
117✔
351
          geometryList->geometries[geometry_simple_index].name;
117✔
352
    if (geometry_aggregate_index >= 0)
318✔
353
      geometry_aggregate_name =
96✔
354
          geometryList->geometries[geometry_aggregate_index].name;
96✔
355

356
    /* get a list of outer rings for this polygon */
357
    outerlist = msGetOuterList(shape);
318✔
358

359
    numouters = 0;
360
    for (i = 0; i < shape->numlines; i++)
653✔
361
      if (outerlist[i] == MS_TRUE)
335✔
362
        numouters++;
324✔
363

364
    if ((geometry_simple_index != -1 && numouters == 1) ||
318✔
365
        (geometry_simple_index != -1 && geometry_aggregate_index == -1) ||
318✔
366
        (geometryList->numgeometries == 0 &&
203✔
367
         shape->numlines == 1)) { /* write a Polygon(s) */
368
      for (i = 0; i < shape->numlines; i++) {
616✔
369
        if (outerlist[i] == MS_FALSE)
311✔
370
          break; /* skip non-outer rings, each outer ring is a new polygon */
371

372
        /* get a list of inner rings for this polygon */
373
        innerlist = msGetInnerList(shape, i, outerlist);
308✔
374

375
        gmlStartGeometryContainer(stream, geometry_simple_name, namespace, tab);
308✔
376

377
        /* Polygon */
378
        if (srsname_encoded)
308✔
379
          msIO_fprintf(stream, "%s<gml:Polygon srsName=\"%s\">\n", tab,
308✔
380
                       srsname_encoded);
381
        else
382
          msIO_fprintf(stream, "%s<gml:Polygon>\n", tab);
×
383

384
        msIO_fprintf(stream, "%s  <gml:outerBoundaryIs>\n", tab);
308✔
385
        msIO_fprintf(stream, "%s    <gml:LinearRing>\n", tab);
308✔
386

387
        msIO_fprintf(stream, "%s      <gml:coordinates>", tab);
308✔
388
        for (j = 0; j < shape->line[i].numpoints; j++) {
21,357✔
389
          if (nSRSDimension == 3)
21,049✔
390
            msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision,
10✔
391
                         shape->line[i].point[j].x, geometry_precision,
392
                         shape->line[i].point[j].y, geometry_precision,
393
                         shape->line[i].point[j].z);
10✔
394
          else
395
            /* fall-through */
396
            msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision,
21,039✔
397
                         shape->line[i].point[j].x, geometry_precision,
398
                         shape->line[i].point[j].y);
21,039✔
399
        }
400
        msIO_fprintf(stream, "</gml:coordinates>\n");
308✔
401

402
        msIO_fprintf(stream, "%s    </gml:LinearRing>\n", tab);
308✔
403
        msIO_fprintf(stream, "%s  </gml:outerBoundaryIs>\n", tab);
308✔
404

405
        for (k = 0; k < shape->numlines;
619✔
406
             k++) { /* now step through all the inner rings */
311✔
407
          if (innerlist[k] == MS_TRUE) {
311✔
408
            msIO_fprintf(stream, "%s  <gml:innerBoundaryIs>\n", tab);
3✔
409
            msIO_fprintf(stream, "%s    <gml:LinearRing>\n", tab);
3✔
410

411
            msIO_fprintf(stream, "%s      <gml:coordinates>", tab);
3✔
412
            for (j = 0; j < shape->line[k].numpoints; j++) {
24✔
413
              if (nSRSDimension == 3)
21✔
414
                msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision,
×
415
                             shape->line[k].point[j].x, geometry_precision,
416
                             shape->line[k].point[j].y, geometry_precision,
417
                             shape->line[k].point[j].z);
×
418
              else
419
                /* fall-through */
420
                msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision,
21✔
421
                             shape->line[k].point[j].x, geometry_precision,
422
                             shape->line[k].point[j].y);
21✔
423
            }
424
            msIO_fprintf(stream, "</gml:coordinates>\n");
3✔
425

426
            msIO_fprintf(stream, "%s    </gml:LinearRing>\n", tab);
3✔
427
            msIO_fprintf(stream, "%s  </gml:innerBoundaryIs>\n", tab);
3✔
428
          }
429
        }
430

431
        msIO_fprintf(stream, "%s</gml:Polygon>\n", tab);
308✔
432
        free(innerlist);
308✔
433

434
        gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab);
308✔
435
      }
436
      free(outerlist);
308✔
437
      outerlist = NULL;
308✔
438
    } else if (geometry_aggregate_index != -1 ||
10✔
439
               (geometryList->numgeometries == 0)) { /* write a MultiPolygon */
440
      gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace,
10✔
441
                                tab);
442

443
      /* MultiPolygon */
444
      if (srsname_encoded)
10✔
445
        msIO_fprintf(stream, "%s<gml:MultiPolygon srsName=\"%s\">\n", tab,
10✔
446
                     srsname_encoded);
447
      else
448
        msIO_fprintf(stream, "%s<gml:MultiPolygon>\n", tab);
×
449

450
      for (i = 0; i < shape->numlines; i++) { /* step through the outer rings */
34✔
451
        if (outerlist[i] == MS_TRUE) {
24✔
452
          innerlist = msGetInnerList(shape, i, outerlist);
16✔
453

454
          msIO_fprintf(stream, "%s<gml:polygonMember>\n", tab);
16✔
455
          msIO_fprintf(stream, "%s  <gml:Polygon>\n", tab);
16✔
456

457
          msIO_fprintf(stream, "%s    <gml:outerBoundaryIs>\n", tab);
16✔
458
          msIO_fprintf(stream, "%s      <gml:LinearRing>\n", tab);
16✔
459

460
          msIO_fprintf(stream, "%s        <gml:coordinates>", tab);
16✔
461
          for (j = 0; j < shape->line[i].numpoints; j++) {
304✔
462
            if (nSRSDimension == 3)
288✔
463
              msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision,
30✔
464
                           shape->line[i].point[j].x, geometry_precision,
465
                           shape->line[i].point[j].y, geometry_precision,
466
                           shape->line[i].point[j].z);
30✔
467
            else
468
              /* fall-through */
469
              msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision,
258✔
470
                           shape->line[i].point[j].x, geometry_precision,
471
                           shape->line[i].point[j].y);
258✔
472
          }
473
          msIO_fprintf(stream, "</gml:coordinates>\n");
16✔
474

475
          msIO_fprintf(stream, "%s      </gml:LinearRing>\n", tab);
16✔
476
          msIO_fprintf(stream, "%s    </gml:outerBoundaryIs>\n", tab);
16✔
477

478
          for (k = 0; k < shape->numlines;
56✔
479
               k++) { /* now step through all the inner rings */
40✔
480
            if (innerlist[k] == MS_TRUE) {
40✔
481
              msIO_fprintf(stream, "%s    <gml:innerBoundaryIs>\n", tab);
8✔
482
              msIO_fprintf(stream, "%s      <gml:LinearRing>\n", tab);
8✔
483

484
              msIO_fprintf(stream, "%s        <gml:coordinates>", tab);
8✔
485
              for (j = 0; j < shape->line[k].numpoints; j++) {
55✔
486
                if (nSRSDimension == 3)
47✔
487
                  msIO_fprintf(stream, "%.*f,%.*f,%.*f ", geometry_precision,
20✔
488
                               shape->line[k].point[j].x, geometry_precision,
489
                               shape->line[k].point[j].y, geometry_precision,
490
                               shape->line[k].point[j].z);
20✔
491
                else
492
                  /* fall-through */
493
                  msIO_fprintf(stream, "%.*f,%.*f ", geometry_precision,
27✔
494
                               shape->line[k].point[j].x, geometry_precision,
495
                               shape->line[k].point[j].y);
27✔
496
              }
497
              msIO_fprintf(stream, "</gml:coordinates>\n");
8✔
498

499
              msIO_fprintf(stream, "%s      </gml:LinearRing>\n", tab);
8✔
500
              msIO_fprintf(stream, "%s    </gml:innerBoundaryIs>\n", tab);
8✔
501
            }
502
          }
503

504
          msIO_fprintf(stream, "%s  </gml:Polygon>\n", tab);
16✔
505
          msIO_fprintf(stream, "%s</gml:polygonMember>\n", tab);
16✔
506

507
          free(innerlist);
16✔
508
        }
509
      }
510
      msIO_fprintf(stream, "%s</gml:MultiPolygon>\n", tab);
10✔
511

512
      free(outerlist);
10✔
513
      outerlist = NULL;
514

515
      gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab);
10✔
516
    } else {
517
      msIO_fprintf(stream, "<!-- Warning: Cannot write geometry- no "
×
518
                           "polygon/multipolygon geometry defined. -->\n");
519
    }
520

521
    break;
522
  default:
523
    break;
524
  }
525

526
  /* clean-up */
527
  msFree(srsname_encoded);
1,504✔
528
  msFree(outerlist);
1,504✔
529

530
  return (MS_SUCCESS);
1,504✔
531
}
532

533
static char *gmlCreateGeomId(OWSGMLVersion nGMLVersion, const char *pszFID,
1,093✔
534
                             int *p_id) {
535
  char *pszGMLId;
536
  if (nGMLVersion == OWS_GML32) {
1,093✔
537
    pszGMLId =
538
        (char *)msSmallMalloc(strlen(pszFID) + 1 + strlen(" gml:id=\"\"") + 10);
892✔
539
    sprintf(pszGMLId, " gml:id=\"%s.%d\"", pszFID, *p_id);
892✔
540
    (*p_id)++;
892✔
541
  } else
542
    pszGMLId = msStrdup("");
201✔
543
  return pszGMLId;
1,093✔
544
}
545

546
/* GML 3.1 or GML 3.2 (MapServer limits GML encoding to the level 0 profile) */
547
static int gmlWriteGeometry_GML3(FILE *stream, gmlGeometryListObj *geometryList,
1,041✔
548
                                 shapeObj *shape, const char *srsname,
549
                                 const char *namespace, const char *tab,
550
                                 const char *pszFID, OWSGMLVersion nGMLVersion,
551
                                 int nSRSDimension, int geometry_precision) {
552
  int i, j, k, id = 1;
1,041✔
553
  int *innerlist, *outerlist = NULL, numouters;
554
  char *srsname_encoded = NULL;
555
  char *pszGMLId;
556

557
  int geometry_aggregate_index, geometry_simple_index;
558
  char *geometry_aggregate_name = NULL, *geometry_simple_name = NULL;
559

560
  if (!stream)
1,041✔
561
    return (MS_FAILURE);
562
  if (!shape)
1,041✔
563
    return (MS_FAILURE);
564
  if (!tab)
1,041✔
565
    return (MS_FAILURE);
566
  if (!geometryList)
1,041✔
567
    return (MS_FAILURE);
568

569
  if (shape->numlines <= 0)
1,041✔
570
    return (MS_SUCCESS); /* empty shape, nothing to output */
571

572
  if (srsname)
1,041✔
573
    srsname_encoded = msEncodeHTMLEntities(srsname);
1,041✔
574

575
  /* feature geometry */
576
  switch (shape->type) {
1,041✔
577
  case (MS_SHAPE_POINT):
200✔
578
    geometry_simple_index = msGMLGeometryLookup(geometryList, "point");
200✔
579
    geometry_aggregate_index = msGMLGeometryLookup(geometryList, "multipoint");
200✔
580
    if (geometry_simple_index >= 0)
200✔
581
      geometry_simple_name =
54✔
582
          geometryList->geometries[geometry_simple_index].name;
54✔
583
    if (geometry_aggregate_index >= 0)
200✔
584
      geometry_aggregate_name =
47✔
585
          geometryList->geometries[geometry_aggregate_index].name;
47✔
586

587
    if ((geometry_simple_index != -1 && shape->line[0].numpoints == 1 &&
200✔
588
         shape->numlines == 1) ||
54✔
589
        (geometry_simple_index != -1 && geometry_aggregate_index == -1) ||
146✔
590
        (geometryList->numgeometries == 0 && shape->line[0].numpoints == 1 &&
146✔
591
         shape->numlines == 1)) { /* write a Point(s) */
134✔
592

593
      for (i = 0; i < shape->numlines; i++) {
374✔
594
        for (j = 0; j < shape->line[i].numpoints; j++) {
374✔
595
          gmlStartGeometryContainer(stream, geometry_simple_name, namespace,
187✔
596
                                    tab);
597

598
          /* Point */
599
          pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id);
187✔
600
          if (srsname_encoded)
187✔
601
            msIO_fprintf(stream, "%s  <gml:Point%s srsName=\"%s\">\n", tab,
187✔
602
                         pszGMLId, srsname_encoded);
603
          else
604
            msIO_fprintf(stream, "%s  <gml:Point%s>\n", tab, pszGMLId);
×
605

606
          if (nSRSDimension == 3)
187✔
607
            msIO_fprintf(
2✔
608
                stream,
609
                "%s    <gml:pos srsDimension=\"3\">%.*f %.*f %.*f</gml:pos>\n",
610
                tab, geometry_precision, shape->line[i].point[j].x,
611
                geometry_precision, shape->line[i].point[j].y,
612
                geometry_precision, shape->line[i].point[j].z);
2✔
613
          else
614
            /* fall-through */
615
            msIO_fprintf(stream, "%s    <gml:pos>%.*f %.*f</gml:pos>\n", tab,
185✔
616
                         geometry_precision, shape->line[i].point[j].x,
617
                         geometry_precision, shape->line[i].point[j].y);
185✔
618

619
          msIO_fprintf(stream, "%s  </gml:Point>\n", tab);
187✔
620

621
          gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab);
187✔
622
          msFree(pszGMLId);
187✔
623
        }
624
      }
625
    } else if ((geometry_aggregate_index != -1) ||
13✔
626
               (geometryList->numgeometries == 0)) { /* write a MultiPoint */
627
      pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id);
13✔
628
      gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace,
13✔
629
                                tab);
630

631
      /* MultiPoint */
632
      if (srsname_encoded)
13✔
633
        msIO_fprintf(stream, "%s  <gml:MultiPoint%s srsName=\"%s\">\n", tab,
13✔
634
                     pszGMLId, srsname_encoded);
635
      else
636
        msIO_fprintf(stream, "%s  <gml:MultiPoint%s>\n", tab, pszGMLId);
×
637

638
      msFree(pszGMLId);
13✔
639

640
      for (i = 0; i < shape->numlines; i++) {
27✔
641
        for (j = 0; j < shape->line[i].numpoints; j++) {
40✔
642
          msIO_fprintf(stream, "%s    <gml:pointMember>\n", tab);
26✔
643
          pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id);
26✔
644
          msIO_fprintf(stream, "%s      <gml:Point%s>\n", tab, pszGMLId);
26✔
645
          if (nSRSDimension == 3)
26✔
646
            msIO_fprintf(stream,
4✔
647
                         "%s        <gml:pos srsDimension=\"3\">%.*f %.*f "
648
                         "%.*f</gml:pos>\n",
649
                         tab, geometry_precision, shape->line[i].point[j].x,
650
                         geometry_precision, shape->line[i].point[j].y,
651
                         geometry_precision, shape->line[i].point[j].z);
4✔
652
          else
653
            /* fall-through */
654
            msIO_fprintf(stream, "%s        <gml:pos>%.*f %.*f</gml:pos>\n",
22✔
655
                         tab, geometry_precision, shape->line[i].point[j].x,
656
                         geometry_precision, shape->line[i].point[j].y);
22✔
657
          msIO_fprintf(stream, "%s      </gml:Point>\n", tab);
26✔
658
          msFree(pszGMLId);
26✔
659
          msIO_fprintf(stream, "%s    </gml:pointMember>\n", tab);
26✔
660
        }
661
      }
662

663
      msIO_fprintf(stream, "%s  </gml:MultiPoint>\n", tab);
13✔
664

665
      gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab);
13✔
666
    } else {
667
      msIO_fprintf(stream, "<!-- Warning: Cannot write geometry- no "
×
668
                           "point/multipoint geometry defined. -->\n");
669
    }
670

671
    break;
672
  case (MS_SHAPE_LINE):
160✔
673
    geometry_simple_index = msGMLGeometryLookup(geometryList, "line");
160✔
674
    geometry_aggregate_index = msGMLGeometryLookup(geometryList, "multiline");
160✔
675
    if (geometry_simple_index >= 0)
160✔
676
      geometry_simple_name =
148✔
677
          geometryList->geometries[geometry_simple_index].name;
148✔
678
    if (geometry_aggregate_index >= 0)
160✔
679
      geometry_aggregate_name =
148✔
680
          geometryList->geometries[geometry_aggregate_index].name;
148✔
681

682
    if ((geometry_simple_index != -1 && shape->numlines == 1) ||
160✔
683
        (geometry_simple_index != -1 && geometry_aggregate_index == -1) ||
12✔
684
        (geometryList->numgeometries == 0 &&
12✔
685
         shape->numlines == 1)) { /* write a LineStrings(s) */
8✔
686
      for (i = 0; i < shape->numlines; i++) {
308✔
687
        gmlStartGeometryContainer(stream, geometry_simple_name, namespace, tab);
154✔
688

689
        /* LineString (should be Curve?) */
690
        pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id);
154✔
691
        if (srsname_encoded)
154✔
692
          msIO_fprintf(stream, "%s  <gml:LineString%s srsName=\"%s\">\n", tab,
154✔
693
                       pszGMLId, srsname_encoded);
694
        else
695
          msIO_fprintf(stream, "%s  <gml:LineString%s>\n", tab, pszGMLId);
×
696
        msFree(pszGMLId);
154✔
697

698
        msIO_fprintf(stream, "%s    <gml:posList srsDimension=\"%d\">", tab,
154✔
699
                     nSRSDimension);
700
        for (j = 0; j < shape->line[i].numpoints; j++) {
3,726✔
701
          if (nSRSDimension == 3)
3,572✔
702
            msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision,
4✔
703
                         shape->line[i].point[j].x, geometry_precision,
704
                         shape->line[i].point[j].y, geometry_precision,
705
                         shape->line[i].point[j].z);
4✔
706
          else
707
            /* fall-through */
708
            msIO_fprintf(stream, "%.*f %.*f ", geometry_precision,
3,568✔
709
                         shape->line[i].point[j].x, geometry_precision,
710
                         shape->line[i].point[j].y);
3,568✔
711
        }
712
        msIO_fprintf(stream, "</gml:posList>\n");
154✔
713

714
        msIO_fprintf(stream, "%s  </gml:LineString>\n", tab);
154✔
715

716
        gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab);
154✔
717
      }
718
    } else if (geometry_aggregate_index != -1 ||
6✔
719
               (geometryList->numgeometries == 0)) { /* write a MultiCurve */
720
      gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace,
6✔
721
                                tab);
722

723
      /* MultiCurve */
724
      pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id);
6✔
725
      if (srsname_encoded)
6✔
726
        msIO_fprintf(stream, "%s  <gml:MultiCurve%s srsName=\"%s\">\n", tab,
6✔
727
                     pszGMLId, srsname_encoded);
728
      else
729
        msIO_fprintf(stream, "%s  <gml:MultiCurve%s>\n", tab, pszGMLId);
×
730
      msFree(pszGMLId);
6✔
731

732
      for (i = 0; i < shape->numlines; i++) {
18✔
733
        msIO_fprintf(stream, "%s    <gml:curveMember>\n", tab);
12✔
734
        pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id);
12✔
735
        msIO_fprintf(stream, "%s      <gml:LineString%s>\n", tab,
12✔
736
                     pszGMLId); /* no srsname at this point */
737
        msFree(pszGMLId);
12✔
738

739
        msIO_fprintf(stream, "%s        <gml:posList srsDimension=\"%d\">", tab,
12✔
740
                     nSRSDimension);
741
        for (j = 0; j < shape->line[i].numpoints; j++) {
36✔
742
          if (nSRSDimension == 3)
24✔
743
            msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision,
8✔
744
                         shape->line[i].point[j].x, geometry_precision,
745
                         shape->line[i].point[j].y, geometry_precision,
746
                         shape->line[i].point[j].z);
8✔
747
          else
748
            /* fall-through */
749
            msIO_fprintf(stream, "%.*f %.*f ", geometry_precision,
16✔
750
                         shape->line[i].point[j].x, geometry_precision,
751
                         shape->line[i].point[j].y);
16✔
752
        }
753

754
        msIO_fprintf(stream, "</gml:posList>\n");
12✔
755
        msIO_fprintf(stream, "%s      </gml:LineString>\n", tab);
12✔
756
        msIO_fprintf(stream, "%s    </gml:curveMember>\n", tab);
12✔
757
      }
758

759
      msIO_fprintf(stream, "%s  </gml:MultiCurve>\n", tab);
6✔
760

761
      gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab);
6✔
762
    } else {
763
      msIO_fprintf(stream, "<!-- Warning: Cannot write geometry- no "
×
764
                           "line/multiline geometry defined. -->\n");
765
    }
766

767
    break;
768
  case (
681✔
769
      MS_SHAPE_POLYGON): /* this gets nasty, since our shapes are so flexible */
770
    geometry_simple_index = msGMLGeometryLookup(geometryList, "polygon");
681✔
771
    geometry_aggregate_index =
772
        msGMLGeometryLookup(geometryList, "multipolygon");
681✔
773
    if (geometry_simple_index >= 0)
681✔
774
      geometry_simple_name =
548✔
775
          geometryList->geometries[geometry_simple_index].name;
548✔
776
    if (geometry_aggregate_index >= 0)
681✔
777
      geometry_aggregate_name =
4✔
778
          geometryList->geometries[geometry_aggregate_index].name;
4✔
779

780
    /* get a list of outer rings for this polygon */
781
    outerlist = msGetOuterList(shape);
681✔
782

783
    numouters = 0;
784
    for (i = 0; i < shape->numlines; i++)
1,380✔
785
      if (outerlist[i] == MS_TRUE)
699✔
786
        numouters++;
687✔
787

788
    if ((geometry_simple_index != -1 && numouters == 1) ||
681✔
789
        (geometry_simple_index != -1 && geometry_aggregate_index == -1) ||
681✔
790
        (geometryList->numgeometries == 0 &&
133✔
791
         shape->numlines == 1)) { /* write a Polygon(s) */
792
      for (i = 0; i < shape->numlines; i++) {
1,346✔
793
        if (outerlist[i] == MS_FALSE)
677✔
794
          break; /* skip non-outer rings, each outer ring is a new polygon */
795

796
        /* get a list of inner rings for this polygon */
797
        innerlist = msGetInnerList(shape, i, outerlist);
673✔
798

799
        gmlStartGeometryContainer(stream, geometry_simple_name, namespace, tab);
673✔
800

801
        pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id);
673✔
802

803
        /* Polygon (should be Surface?) */
804
        if (srsname_encoded)
673✔
805
          msIO_fprintf(stream, "%s  <gml:Polygon%s srsName=\"%s\">\n", tab,
673✔
806
                       pszGMLId, srsname_encoded);
807
        else
808
          msIO_fprintf(stream, "%s  <gml:Polygon%s>\n", tab, pszGMLId);
×
809
        msFree(pszGMLId);
673✔
810

811
        msIO_fprintf(stream, "%s    <gml:exterior>\n", tab);
673✔
812
        msIO_fprintf(stream, "%s      <gml:LinearRing>\n", tab);
673✔
813

814
        msIO_fprintf(stream, "%s        <gml:posList srsDimension=\"%d\">", tab,
673✔
815
                     nSRSDimension);
816
        for (j = 0; j < shape->line[i].numpoints; j++) {
53,887✔
817
          if (nSRSDimension == 3)
53,214✔
818
            msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision,
10✔
819
                         shape->line[i].point[j].x, geometry_precision,
820
                         shape->line[i].point[j].y, geometry_precision,
821
                         shape->line[i].point[j].z);
10✔
822
          else
823
            /* fall-through */
824
            msIO_fprintf(stream, "%.*f %.*f ", geometry_precision,
53,204✔
825
                         shape->line[i].point[j].x, geometry_precision,
826
                         shape->line[i].point[j].y);
53,204✔
827
        }
828

829
        msIO_fprintf(stream, "</gml:posList>\n");
673✔
830

831
        msIO_fprintf(stream, "%s      </gml:LinearRing>\n", tab);
673✔
832
        msIO_fprintf(stream, "%s    </gml:exterior>\n", tab);
673✔
833

834
        for (k = 0; k < shape->numlines;
1,350✔
835
             k++) { /* now step through all the inner rings */
677✔
836
          if (innerlist[k] == MS_TRUE) {
677✔
837
            msIO_fprintf(stream, "%s    <gml:interior>\n", tab);
4✔
838
            msIO_fprintf(stream, "%s      <gml:LinearRing>\n", tab);
4✔
839

840
            msIO_fprintf(stream, "%s        <gml:posList srsDimension=\"%d\">",
4✔
841
                         tab, nSRSDimension);
842
            for (j = 0; j < shape->line[k].numpoints; j++) {
24✔
843
              if (nSRSDimension == 3)
20✔
844
                msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision,
×
845
                             shape->line[k].point[j].x, geometry_precision,
846
                             shape->line[k].point[j].y, geometry_precision,
847
                             shape->line[k].point[j].z);
×
848
              else
849
                /* fall-through */
850
                msIO_fprintf(stream, "%.*f %.*f ", geometry_precision,
20✔
851
                             shape->line[k].point[j].x, geometry_precision,
852
                             shape->line[k].point[j].y);
20✔
853
            }
854

855
            msIO_fprintf(stream, "</gml:posList>\n");
4✔
856

857
            msIO_fprintf(stream, "%s      </gml:LinearRing>\n", tab);
4✔
858
            msIO_fprintf(stream, "%s    </gml:interior>\n", tab);
4✔
859
          }
860
        }
861

862
        msIO_fprintf(stream, "%s  </gml:Polygon>\n", tab);
673✔
863
        free(innerlist);
673✔
864

865
        gmlEndGeometryContainer(stream, geometry_simple_name, namespace, tab);
673✔
866
      }
867
      free(outerlist);
673✔
868
      outerlist = NULL;
673✔
869
    } else if (geometry_aggregate_index != -1 ||
8✔
870
               (geometryList->numgeometries == 0)) { /* write a MultiSurface */
871
      gmlStartGeometryContainer(stream, geometry_aggregate_name, namespace,
8✔
872
                                tab);
873

874
      pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id);
8✔
875

876
      /* MultiSurface */
877
      if (srsname_encoded)
8✔
878
        msIO_fprintf(stream, "%s  <gml:MultiSurface%s srsName=\"%s\">\n", tab,
8✔
879
                     pszGMLId, srsname_encoded);
880
      else
881
        msIO_fprintf(stream, "%s  <gml:MultiSurface%s>\n", tab, pszGMLId);
×
882
      msFree(pszGMLId);
8✔
883

884
      for (i = 0; i < shape->numlines; i++) { /* step through the outer rings */
30✔
885
        if (outerlist[i] == MS_TRUE) {
22✔
886
          msIO_fprintf(stream, "%s    <gml:surfaceMember>\n", tab);
14✔
887

888
          /* get a list of inner rings for this polygon */
889
          innerlist = msGetInnerList(shape, i, outerlist);
14✔
890

891
          pszGMLId = gmlCreateGeomId(nGMLVersion, pszFID, &id);
14✔
892

893
          msIO_fprintf(stream, "%s      <gml:Polygon%s>\n", tab, pszGMLId);
14✔
894
          msFree(pszGMLId);
14✔
895

896
          msIO_fprintf(stream, "%s        <gml:exterior>\n", tab);
14✔
897
          msIO_fprintf(stream, "%s          <gml:LinearRing>\n", tab);
14✔
898

899
          msIO_fprintf(stream,
14✔
900
                       "%s            <gml:posList srsDimension=\"%d\">", tab,
901
                       nSRSDimension);
902
          for (j = 0; j < shape->line[i].numpoints; j++) {
84✔
903
            if (nSRSDimension == 3)
70✔
904
              msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision,
30✔
905
                           shape->line[i].point[j].x, geometry_precision,
906
                           shape->line[i].point[j].y, geometry_precision,
907
                           shape->line[i].point[j].z);
30✔
908
            else
909
              /* fall-through */
910
              msIO_fprintf(stream, "%.*f %.*f ", geometry_precision,
40✔
911
                           shape->line[i].point[j].x, geometry_precision,
912
                           shape->line[i].point[j].y);
40✔
913
          }
914

915
          msIO_fprintf(stream, "</gml:posList>\n");
14✔
916

917
          msIO_fprintf(stream, "%s          </gml:LinearRing>\n", tab);
14✔
918
          msIO_fprintf(stream, "%s        </gml:exterior>\n", tab);
14✔
919

920
          for (k = 0; k < shape->numlines;
54✔
921
               k++) { /* now step through all the inner rings */
40✔
922
            if (innerlist[k] == MS_TRUE) {
40✔
923
              msIO_fprintf(stream, "%s        <gml:interior>\n", tab);
8✔
924
              msIO_fprintf(stream, "%s          <gml:LinearRing>\n", tab);
8✔
925

926
              msIO_fprintf(stream,
8✔
927
                           "%s            <gml:posList srsDimension=\"%d\">",
928
                           tab, nSRSDimension);
929
              for (j = 0; j < shape->line[k].numpoints; j++) {
48✔
930
                if (nSRSDimension == 3)
40✔
931
                  msIO_fprintf(stream, "%.*f %.*f %.*f ", geometry_precision,
20✔
932
                               shape->line[k].point[j].x, geometry_precision,
933
                               shape->line[k].point[j].y, geometry_precision,
934
                               shape->line[k].point[j].z);
20✔
935
                else
936
                  /* fall-through */
937
                  msIO_fprintf(stream, "%.*f %.*f ", geometry_precision,
20✔
938
                               shape->line[k].point[j].x, geometry_precision,
939
                               shape->line[k].point[j].y);
20✔
940
              }
941
              msIO_fprintf(stream, "</gml:posList>\n");
8✔
942

943
              msIO_fprintf(stream, "%s          </gml:LinearRing>\n", tab);
8✔
944
              msIO_fprintf(stream, "%s        </gml:interior>\n", tab);
8✔
945
            }
946
          }
947

948
          msIO_fprintf(stream, "%s      </gml:Polygon>\n", tab);
14✔
949

950
          free(innerlist);
14✔
951
          msIO_fprintf(stream, "%s    </gml:surfaceMember>\n", tab);
14✔
952
        }
953
      }
954
      msIO_fprintf(stream, "%s  </gml:MultiSurface>\n", tab);
8✔
955

956
      free(outerlist);
8✔
957
      outerlist = NULL;
958

959
      gmlEndGeometryContainer(stream, geometry_aggregate_name, namespace, tab);
8✔
960
    } else {
961
      msIO_fprintf(stream, "<!-- Warning: Cannot write geometry- no "
×
962
                           "polygon/multipolygon geometry defined. -->\n");
963
    }
964

965
    break;
966
  default:
967
    break;
968
  }
969

970
  /* clean-up */
971
  msFree(outerlist);
1,041✔
972
  msFree(srsname_encoded);
1,041✔
973

974
  return (MS_SUCCESS);
1,041✔
975
}
976

977
/*
978
** Wrappers for the format specific encoding functions.
979
*/
980
static int gmlWriteBounds(FILE *stream, OWSGMLVersion format, rectObj *rect,
2,943✔
981
                          const char *srsname, const char *tab,
982
                          const char *pszTopPrefix) {
983
  switch (format) {
2,943✔
984
  case (OWS_GML2):
1,761✔
985
    return gmlWriteBounds_GML2(stream, rect, srsname, tab, pszTopPrefix);
1,761✔
986
    break;
987
  case (OWS_GML3):
1,182✔
988
  case (OWS_GML32):
989
    return gmlWriteBounds_GML3(stream, rect, srsname, tab, pszTopPrefix);
1,182✔
990
    break;
991
  default:
×
992
    msSetError(MS_IOERR, "Unsupported GML format.", "gmlWriteBounds()");
×
993
  }
994

995
  return (MS_FAILURE);
×
996
}
997

998
static int gmlWriteGeometry(FILE *stream, gmlGeometryListObj *geometryList,
2,545✔
999
                            OWSGMLVersion format, shapeObj *shape,
1000
                            const char *srsname, const char *namespace,
1001
                            const char *tab, const char *pszFID,
1002
                            int nSRSDimension, int geometry_precision) {
1003
  switch (format) {
2,545✔
1004
  case (OWS_GML2):
1,504✔
1005
    return gmlWriteGeometry_GML2(stream, geometryList, shape, srsname,
1,504✔
1006
                                 namespace, tab, nSRSDimension,
1007
                                 geometry_precision);
1008
    break;
1009
  case (OWS_GML3):
1,041✔
1010
  case (OWS_GML32):
1011
    return gmlWriteGeometry_GML3(stream, geometryList, shape, srsname,
1,041✔
1012
                                 namespace, tab, pszFID, format, nSRSDimension,
1013
                                 geometry_precision);
1014
    break;
1015
  default:
×
1016
    msSetError(MS_IOERR, "Unsupported GML format.", "gmlWriteGeometry()");
×
1017
  }
1018

1019
  return (MS_FAILURE);
×
1020
}
1021

1022
/*
1023
** GML specific metadata handling functions.
1024
*/
1025

1026
int msItemInGroups(const char *name, gmlGroupListObj *groupList) {
29,278✔
1027
  int i, j;
1028
  gmlGroupObj *group;
1029

1030
  if (!groupList)
29,278✔
1031
    return MS_FALSE; /* no groups */
1032

1033
  for (i = 0; i < groupList->numgroups; i++) {
31,647✔
1034
    group = &(groupList->groups[i]);
3,194✔
1035
    for (j = 0; j < group->numitems; j++) {
11,126✔
1036
      if (strcasecmp(name, group->items[j]) == 0)
8,757✔
1037
        return MS_TRUE;
1038
    }
1039
  }
1040

1041
  return MS_FALSE;
1042
}
1043

1044
static int msGMLGeometryLookup(gmlGeometryListObj *geometryList,
5,090✔
1045
                               const char *type) {
1046
  int i;
1047

1048
  if (!geometryList || !type)
5,090✔
1049
    return -1; /* nothing to look for */
1050

1051
  for (i = 0; i < geometryList->numgeometries; i++)
6,254✔
1052
    if (geometryList->geometries[i].type &&
1,784✔
1053
        (strcasecmp(geometryList->geometries[i].type, type) == 0))
1,238✔
1054
      return i;
620✔
1055

1056
  if (geometryList->numgeometries == 1 &&
4,470✔
1057
      geometryList->geometries[0].type == NULL)
1,162✔
1058
    return 0;
546✔
1059

1060
  return -1; /* not found */
1061
}
1062

1063
gmlGeometryListObj *msGMLGetGeometries(layerObj *layer,
1,190✔
1064
                                       const char *metadata_namespaces,
1065
                                       int bWithDefaultGeom) {
1066
  int i;
1067

1068
  const char *value = NULL;
1069
  char tag[64];
1070

1071
  char **names = NULL;
1072
  int numnames = 0;
1,190✔
1073

1074
  gmlGeometryListObj *geometryList = NULL;
1075
  gmlGeometryObj *geometry = NULL;
1076

1077
  /* allocate memory and initialize the item collection */
1078
  geometryList = (gmlGeometryListObj *)malloc(sizeof(gmlGeometryListObj));
1,190✔
1079
  MS_CHECK_ALLOC(geometryList, sizeof(gmlGeometryListObj), NULL);
1,190✔
1080
  geometryList->geometries = NULL;
1,190✔
1081
  geometryList->numgeometries = 0;
1,190✔
1082

1083
  if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
1,190✔
1084
                                   "geometries")) != NULL) {
1085
    names = msStringSplit(value, ',', &numnames);
359✔
1086

1087
    /* allocation an array of gmlGeometryObj's */
1088
    geometryList->numgeometries = numnames;
359✔
1089
    geometryList->geometries = (gmlGeometryObj *)malloc(
359✔
1090
        sizeof(gmlGeometryObj) * geometryList->numgeometries);
359✔
1091
    if (geometryList->geometries == NULL) {
359✔
1092
      msSetError(
×
1093
          MS_MEMERR, "Out of memory allocating %u bytes.\n",
1094
          "msGMLGetGeometries()",
1095
          (unsigned int)(sizeof(gmlGeometryObj) * geometryList->numgeometries));
1096
      free(geometryList);
×
1097
      return NULL;
×
1098
    }
1099

1100
    for (i = 0; i < geometryList->numgeometries; i++) {
721✔
1101
      geometry = &(geometryList->geometries[i]);
362✔
1102

1103
      geometry->name = msStrdup(names[i]); /* initialize a few things */
362✔
1104
      geometry->type = NULL;
362✔
1105
      geometry->occurmin = 0;
362✔
1106
      geometry->occurmax = 1;
362✔
1107

1108
      snprintf(tag, 64, "%s_type", names[i]);
362✔
1109
      if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
362✔
1110
                                       tag)) != NULL)
1111
        geometry->type = msStrdup(value); /* TODO: validate input value */
323✔
1112

1113
      snprintf(tag, 64, "%s_occurances", names[i]);
362✔
1114
      if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
362✔
1115
                                       tag)) != NULL) {
1116
        char **occur;
1117
        int numoccur;
1118

1119
        occur = msStringSplit(value, ',', &numoccur);
×
1120
        if (numoccur == 2) { /* continue (TODO: throw an error if != 2) */
×
1121
          geometry->occurmin = atof(occur[0]);
×
1122
          if (strcasecmp(occur[1], "UNBOUNDED") == 0)
×
1123
            geometry->occurmax = OWS_GML_OCCUR_UNBOUNDED;
×
1124
          else
1125
            geometry->occurmax = atof(occur[1]);
×
1126
        }
1127
        msFreeCharArray(occur, numoccur);
×
1128
      }
1129
    }
1130

1131
    msFreeCharArray(names, numnames);
359✔
1132
  } else if (bWithDefaultGeom) {
831✔
1133
    geometryList->numgeometries = 1;
485✔
1134
    geometryList->geometries =
485✔
1135
        (gmlGeometryObj *)calloc(1, sizeof(gmlGeometryObj));
485✔
1136
    geometryList->geometries[0].name = msStrdup(OWS_GML_DEFAULT_GEOMETRY_NAME);
485✔
1137
    geometryList->geometries[0].type = NULL;
485✔
1138
    geometryList->geometries[0].occurmin = 0;
485✔
1139
    geometryList->geometries[0].occurmax = 1;
485✔
1140
  }
1141

1142
  return geometryList;
1143
}
1144

1145
void msGMLFreeGeometries(gmlGeometryListObj *geometryList) {
1,190✔
1146
  int i;
1147

1148
  if (!geometryList)
1,190✔
1149
    return;
1150

1151
  for (i = 0; i < geometryList->numgeometries; i++) {
2,037✔
1152
    msFree(geometryList->geometries[i].name);
847✔
1153
    msFree(geometryList->geometries[i].type);
847✔
1154
  }
1155
  free(geometryList->geometries);
1,190✔
1156

1157
  free(geometryList);
1,190✔
1158
}
1159

1160
static void msGMLWriteItem(FILE *stream, gmlItemObj *item, const char *value,
28,922✔
1161
                           const char *namespace, const char *tab,
1162
                           OWSGMLVersion outputformat, const char *pszFID) {
1163
  char *encoded_value = NULL, *tag_name;
1164
  int add_namespace = MS_TRUE;
1165
  char gmlid[256];
1166
  gmlid[0] = 0;
28,922✔
1167

1168
  if (!stream || !item)
28,922✔
1169
    return;
1170
  if (!item->visible)
28,922✔
1171
    return;
1172

1173
  if (!namespace)
15,926✔
1174
    add_namespace = MS_FALSE;
1175

1176
  if (item->alias)
15,926✔
1177
    tag_name = item->alias;
1178
  else
1179
    tag_name = item->name;
15,640✔
1180
  if (strchr(tag_name, ':') != NULL)
15,926✔
1181
    add_namespace = MS_FALSE;
1182

1183
  if (item->type &&
15,926✔
1184
      (EQUAL(item->type, "Date") || EQUAL(item->type, "DateTime") ||
3,771✔
1185
       EQUAL(item->type, "Time"))) {
3,672✔
1186
    struct tm tm;
1187
    if (msParseTime(value, &tm) == MS_TRUE) {
108✔
1188
      const char *pszStartTag = "";
1189
      const char *pszEndTag = "";
1190

1191
      encoded_value = (char *)msSmallMalloc(256);
106✔
1192
      if (outputformat == OWS_GML32) {
106✔
1193
        if (pszFID != NULL)
86✔
1194
          snprintf(gmlid, 256, " gml:id=\"%s.%s\"", pszFID, tag_name);
1195
        pszStartTag = "<gml:timePosition>";
1196
        pszEndTag = "</gml:timePosition>";
1197
      }
1198

1199
      if (EQUAL(item->type, "Date"))
106✔
1200
        snprintf(encoded_value, 256, "%s%04d-%02d-%02d%s", pszStartTag,
58✔
1201
                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, pszEndTag);
58✔
1202
      else if (EQUAL(item->type, "Time"))
48✔
1203
        snprintf(encoded_value, 256, "%s%02d:%02d:%02dZ%s", pszStartTag,
8✔
1204
                 tm.tm_hour, tm.tm_min, tm.tm_sec, pszEndTag);
1205
      else {
1206
        // Detected date time already formatted as YYYY-MM-DDTHH:mm:SS+ab:cd
1207
        // because msParseTime() can't handle time zones.
1208
        if (strlen(value) ==
40✔
1209
                4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 &&
1✔
1210
            value[4] == '-' && value[7] == '-' && value[10] == 'T' &&
1✔
1211
            value[13] == ':' && value[16] == ':' &&
1✔
1212
            (value[19] == '+' || value[19] == '-') && value[22] == ':') {
1✔
1213
          snprintf(encoded_value, 256, "%s%s%s", pszStartTag, value, pszEndTag);
1214
        } else {
1215
          snprintf(encoded_value, 256, "%s%04d-%02d-%02dT%02d:%02d:%02dZ%s",
39✔
1216
                   pszStartTag, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
39✔
1217
                   tm.tm_hour, tm.tm_min, tm.tm_sec, pszEndTag);
1218
        }
1219
      }
1220
    }
1221
  }
1222

1223
  if (encoded_value == NULL) {
106✔
1224
    if (item->encode == MS_TRUE)
15,820✔
1225
      encoded_value = msEncodeHTMLEntities(value);
15,820✔
1226
    else
1227
      encoded_value = msStrdup(value);
×
1228
  }
1229

1230
  if (!item->template) { /* build the tag from pieces */
15,926✔
1231

1232
    if (add_namespace == MS_TRUE && msIsXMLTagValid(tag_name) == MS_FALSE)
15,926✔
1233
      msIO_fprintf(stream,
8✔
1234
                   "<!-- WARNING: The value '%s' is not valid in a XML tag "
1235
                   "context. -->\n",
1236
                   tag_name);
1237

1238
    if (add_namespace == MS_TRUE)
1239
      msIO_fprintf(stream, "%s<%s:%s%s>%s</%s:%s>\n", tab, namespace, tag_name,
15,253✔
1240
                   gmlid, encoded_value, namespace, tag_name);
1241
    else
1242
      msIO_fprintf(stream, "%s<%s%s>%s</%s>\n", tab, tag_name, gmlid,
673✔
1243
                   encoded_value, tag_name);
1244
  } else {
1245
    char *tag = NULL;
1246

1247
    tag = msStrdup(item->template);
×
1248
    tag = msReplaceSubstring(tag, "$value", encoded_value);
×
1249
    if (namespace)
×
1250
      tag = msReplaceSubstring(tag, "$namespace", namespace);
×
1251
    msIO_fprintf(stream, "%s%s\n", tab, tag);
×
1252
    free(tag);
×
1253
  }
1254

1255
  free(encoded_value);
15,926✔
1256

1257
  return;
15,926✔
1258
}
1259

1260
gmlNamespaceListObj *msGMLGetNamespaces(webObj *web,
596✔
1261
                                        const char *metadata_namespaces) {
1262
  int i;
1263
  const char *value = NULL;
1264
  char tag[64];
1265

1266
  char **prefixes = NULL;
1267
  int numprefixes = 0;
596✔
1268

1269
  gmlNamespaceListObj *namespaceList = NULL;
1270
  gmlNamespaceObj *namespace = NULL;
1271

1272
  /* allocate the collection */
1273
  namespaceList = (gmlNamespaceListObj *)malloc(sizeof(gmlNamespaceListObj));
596✔
1274
  MS_CHECK_ALLOC(namespaceList, sizeof(gmlNamespaceListObj), NULL);
596✔
1275
  namespaceList->namespaces = NULL;
596✔
1276
  namespaceList->numnamespaces = 0;
596✔
1277

1278
  /* list of namespaces (TODO: make this automatic by parsing metadata) */
1279
  if ((value = msOWSLookupMetadata(&(web->metadata), metadata_namespaces,
596✔
1280
                                   "external_namespace_prefixes")) != NULL) {
1281
    prefixes = msStringSplit(value, ',', &numprefixes);
×
1282

1283
    /* allocation an array of gmlNamespaceObj's */
1284
    namespaceList->numnamespaces = numprefixes;
×
1285
    namespaceList->namespaces = (gmlNamespaceObj *)malloc(
×
1286
        sizeof(gmlNamespaceObj) * namespaceList->numnamespaces);
×
1287
    if (namespaceList->namespaces == NULL) {
×
1288
      msSetError(MS_MEMERR, "Out of memory allocating %u bytes.\n",
×
1289
                 "msGMLGetNamespaces()",
1290
                 (unsigned int)(sizeof(gmlNamespaceObj) *
1291
                                namespaceList->numnamespaces));
1292
      free(namespaceList);
×
1293
      return NULL;
×
1294
    }
1295

1296
    for (i = 0; i < namespaceList->numnamespaces; i++) {
×
1297
      namespace = &(namespaceList->namespaces[i]);
×
1298

1299
      namespace->prefix = msStrdup(prefixes[i]); /* initialize a few things */
×
1300
      namespace->uri = NULL;
×
1301
      namespace->schemalocation = NULL;
×
1302

1303
      snprintf(tag, 64, "%s_uri", namespace->prefix);
1304
      if ((value = msOWSLookupMetadata(&(web->metadata), metadata_namespaces,
×
1305
                                       tag)) != NULL)
1306
      namespace->uri = msStrdup(value);
×
1307

1308
      snprintf(tag, 64, "%s_schema_location", namespace->prefix);
×
1309
      if ((value = msOWSLookupMetadata(&(web->metadata), metadata_namespaces,
×
1310
                                       tag)) != NULL)
1311
      namespace->schemalocation = msStrdup(value);
×
1312
    }
1313

1314
    msFreeCharArray(prefixes, numprefixes);
×
1315
  }
1316

1317
  return namespaceList;
1318
}
1319

1320
void msGMLFreeNamespaces(gmlNamespaceListObj *namespaceList) {
596✔
1321
  int i;
1322

1323
  if (!namespaceList)
596✔
1324
    return;
1325

1326
  for (i = 0; i < namespaceList->numnamespaces; i++) {
596✔
1327
    msFree(namespaceList->namespaces[i].prefix);
×
1328
    msFree(namespaceList->namespaces[i].uri);
×
1329
    msFree(namespaceList->namespaces[i].schemalocation);
×
1330
  }
1331

1332
  free(namespaceList);
596✔
1333
}
1334

1335
gmlConstantListObj *msGMLGetConstants(layerObj *layer,
552✔
1336
                                      const char *metadata_namespaces) {
1337
  int i;
1338
  const char *value = NULL;
1339
  char tag[64];
1340

1341
  char **names = NULL;
1342
  int numnames = 0;
552✔
1343

1344
  gmlConstantListObj *constantList = NULL;
1345
  gmlConstantObj *constant = NULL;
1346

1347
  /* allocate the collection */
1348
  constantList = (gmlConstantListObj *)malloc(sizeof(gmlConstantListObj));
552✔
1349
  MS_CHECK_ALLOC(constantList, sizeof(gmlConstantListObj), NULL);
552✔
1350
  constantList->constants = NULL;
552✔
1351
  constantList->numconstants = 0;
552✔
1352

1353
  /* list of constants (TODO: make this automatic by parsing metadata) */
1354
  if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
552✔
1355
                                   "constants")) != NULL) {
1356
    names = msStringSplit(value, ',', &numnames);
×
1357

1358
    /* allocation an array of gmlConstantObj's */
1359
    constantList->numconstants = numnames;
×
1360
    constantList->constants = (gmlConstantObj *)malloc(
×
1361
        sizeof(gmlConstantObj) * constantList->numconstants);
×
1362
    if (constantList->constants == NULL) {
×
1363
      msSetError(
×
1364
          MS_MEMERR, "Out of memory allocating %u bytes.\n",
1365
          "msGMLGetConstants()",
1366
          (unsigned int)(sizeof(gmlConstantObj) * constantList->numconstants));
1367
      free(constantList);
×
1368
      return NULL;
×
1369
    }
1370

1371
    for (i = 0; i < constantList->numconstants; i++) {
×
1372
      constant = &(constantList->constants[i]);
×
1373

1374
      constant->name = msStrdup(names[i]); /* initialize a few things */
×
1375
      constant->value = NULL;
×
1376
      constant->type = NULL;
×
1377

1378
      snprintf(tag, 64, "%s_value", constant->name);
1379
      if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
×
1380
                                       tag)) != NULL)
1381
        constant->value = msStrdup(value);
×
1382

1383
      snprintf(tag, 64, "%s_type", constant->name);
×
1384
      if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
×
1385
                                       tag)) != NULL)
1386
        constant->type = msStrdup(value);
×
1387
    }
1388

1389
    msFreeCharArray(names, numnames);
×
1390
  }
1391

1392
  return constantList;
1393
}
1394

1395
void msGMLFreeConstants(gmlConstantListObj *constantList) {
552✔
1396
  int i;
1397

1398
  if (!constantList)
552✔
1399
    return;
1400

1401
  for (i = 0; i < constantList->numconstants; i++) {
552✔
1402
    msFree(constantList->constants[i].name);
×
1403
    msFree(constantList->constants[i].value);
×
1404
    msFree(constantList->constants[i].type);
×
1405
  }
1406

1407
  free(constantList);
552✔
1408
}
1409

1410
static void msGMLWriteConstant(FILE *stream, gmlConstantObj *constant,
×
1411
                               const char *namespace, const char *tab) {
1412
  int add_namespace = MS_TRUE;
1413

1414
  if (!stream || !constant)
×
1415
    return;
1416
  if (!constant->value)
×
1417
    return;
1418

1419
  if (!namespace)
×
1420
    add_namespace = MS_FALSE;
1421
  if (strchr(constant->name, ':') != NULL)
×
1422
    add_namespace = MS_FALSE;
1423

1424
  if (add_namespace == MS_TRUE && msIsXMLTagValid(constant->name) == MS_FALSE)
×
1425
    msIO_fprintf(
×
1426
        stream,
1427
        "<!-- WARNING: The value '%s' is not valid in a XML tag context. -->\n",
1428
        constant->name);
1429

1430
  if (add_namespace == MS_TRUE)
×
1431
    msIO_fprintf(stream, "%s<%s:%s>%s</%s:%s>\n", tab, namespace,
×
1432
                 constant->name, constant->value, namespace, constant->name);
1433
  else
1434
    msIO_fprintf(stream, "%s<%s>%s</%s>\n", tab, constant->name,
×
1435
                 constant->value, constant->name);
1436

1437
  return;
1438
}
1439

1440
static void msGMLWriteGroup(FILE *stream, gmlGroupObj *group, shapeObj *shape,
273✔
1441
                            gmlItemListObj *itemList,
1442
                            gmlConstantListObj *constantList,
1443
                            const char *namespace, const char *tab,
1444
                            OWSGMLVersion outputformat, const char *pszFID) {
1445
  int i, j;
1446
  int add_namespace = MS_TRUE;
1447
  char *itemtab;
1448

1449
  gmlItemObj *item = NULL;
1450
  gmlConstantObj *constant = NULL;
1451

1452
  if (!stream || !group)
273✔
1453
    return;
1454

1455
  /* setup the item/constant tab */
1456
  itemtab = (char *)msSmallMalloc(sizeof(char) * strlen(tab) + 3);
273✔
1457

1458
  sprintf(itemtab, "%s  ", tab);
1459

1460
  if (!namespace || strchr(group->name, ':') != NULL)
273✔
1461
    add_namespace = MS_FALSE;
1462

1463
  /* start the group */
1464
  if (add_namespace == MS_TRUE)
1465
    msIO_fprintf(stream, "%s<%s:%s>\n", tab, namespace, group->name);
273✔
1466
  else
1467
    msIO_fprintf(stream, "%s<%s>\n", tab, group->name);
×
1468

1469
  /* now the items/constants in the group */
1470
  for (i = 0; i < group->numitems; i++) {
1,092✔
1471
    for (j = 0; j < constantList->numconstants; j++) {
819✔
1472
      constant = &(constantList->constants[j]);
×
1473
      if (strcasecmp(constant->name, group->items[i]) == 0) {
×
1474
        msGMLWriteConstant(stream, constant, namespace, itemtab);
×
1475
        break;
×
1476
      }
1477
    }
1478
    if (j != constantList->numconstants)
819✔
1479
      continue; /* found this one */
×
1480
    for (j = 0; j < itemList->numitems; j++) {
7,623✔
1481
      item = &(itemList->items[j]);
7,623✔
1482
      if (strcasecmp(item->name, group->items[i]) == 0) {
7,623✔
1483
        /* the number of items matches the number of values exactly */
1484
        msGMLWriteItem(stream, item, shape->values[j], namespace, itemtab,
819✔
1485
                       outputformat, pszFID);
1486
        break;
819✔
1487
      }
1488
    }
1489
  }
1490

1491
  /* end the group */
1492
  if (add_namespace == MS_TRUE)
273✔
1493
    msIO_fprintf(stream, "%s</%s:%s>\n", tab, namespace, group->name);
273✔
1494
  else
1495
    msIO_fprintf(stream, "%s</%s>\n", tab, group->name);
×
1496

1497
  msFree(itemtab);
273✔
1498

1499
  return;
273✔
1500
}
1501
#endif
1502

1503
gmlGroupListObj *msGMLGetGroups(layerObj *layer,
1,620✔
1504
                                const char *metadata_namespaces) {
1505
  int i;
1506
  const char *value = NULL;
1507
  char tag[64];
1508

1509
  char **names = NULL;
1510
  int numnames = 0;
1,620✔
1511

1512
  gmlGroupListObj *groupList = NULL;
1513
  gmlGroupObj *group = NULL;
1514

1515
  /* allocate the collection */
1516
  groupList = (gmlGroupListObj *)malloc(sizeof(gmlGroupListObj));
1,620✔
1517
  MS_CHECK_ALLOC(groupList, sizeof(gmlGroupListObj), NULL);
1,620✔
1518
  groupList->groups = NULL;
1,620✔
1519
  groupList->numgroups = 0;
1,620✔
1520

1521
  /* list of groups (TODO: make this automatic by parsing metadata) */
1522
  if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
1,620✔
1523
                                   "groups")) != NULL &&
35✔
1524
      value[0] != '\0') {
35✔
1525
    names = msStringSplit(value, ',', &numnames);
22✔
1526

1527
    /* allocation an array of gmlGroupObj's */
1528
    groupList->numgroups = numnames;
22✔
1529
    groupList->groups =
22✔
1530
        (gmlGroupObj *)malloc(sizeof(gmlGroupObj) * groupList->numgroups);
22✔
1531
    if (groupList->groups == NULL) {
22✔
1532
      msSetError(MS_MEMERR, "Out of memory allocating %u bytes.\n",
×
1533
                 "msGMLGetGroups()",
1534
                 (unsigned int)(sizeof(gmlGroupObj) * groupList->numgroups));
1535
      free(groupList);
×
1536
      return NULL;
×
1537
    }
1538

1539
    for (i = 0; i < groupList->numgroups; i++) {
65✔
1540
      group = &(groupList->groups[i]);
43✔
1541

1542
      group->name = msStrdup(names[i]); /* initialize a few things */
43✔
1543
      group->items = NULL;
43✔
1544
      group->numitems = 0;
43✔
1545
      group->type = NULL;
43✔
1546

1547
      snprintf(tag, 64, "%s_group", group->name);
1548
      if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
43✔
1549
                                       tag)) != NULL)
1550
        group->items = msStringSplit(value, ',', &group->numitems);
43✔
1551

1552
      snprintf(tag, 64, "%s_type", group->name);
43✔
1553
      if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
43✔
1554
                                       tag)) != NULL)
1555
        group->type = msStrdup(value);
×
1556
    }
1557

1558
    msFreeCharArray(names, numnames);
22✔
1559
  }
1560

1561
  return groupList;
1562
}
1563

1564
void msGMLFreeGroups(gmlGroupListObj *groupList) {
1,620✔
1565
  int i;
1566

1567
  if (!groupList)
1,620✔
1568
    return;
1569

1570
  for (i = 0; i < groupList->numgroups; i++) {
1,663✔
1571
    msFree(groupList->groups[i].name);
43✔
1572
    msFreeCharArray(groupList->groups[i].items, groupList->groups[i].numitems);
43✔
1573
    msFree(groupList->groups[i].type);
43✔
1574
  }
1575
  msFree(groupList->groups);
1,620✔
1576

1577
  free(groupList);
1,620✔
1578
}
1579

1580
/* Dump GML query results for WMS GetFeatureInfo */
1581
int msGMLWriteQuery(mapObj *map, char *filename, const char *namespaces) {
33✔
1582
#if defined(USE_WMS_SVR)
1583
  int status;
1584
  int i, j, k;
1585
  layerObj *lp = NULL;
1586
  shapeObj shape;
1587
  FILE *stream_to_free = NULL;
1588
  FILE *stream = stdout; /* defaults to stdout */
33✔
1589
  char szPath[MS_MAXPATHLEN];
1590
  char *value;
1591
  char *pszMapSRS = NULL;
33✔
1592

1593
  gmlGroupListObj *groupList = NULL;
1594
  gmlItemListObj *itemList = NULL;
1595
  gmlConstantListObj *constantList = NULL;
1596
  gmlGeometryListObj *geometryList = NULL;
1597
  gmlItemObj *item = NULL;
1598
  gmlConstantObj *constant = NULL;
1599

1600
  msInitShape(&shape);
33✔
1601

1602
  if (filename &&
33✔
1603
      strlen(filename) > 0) { /* deal with the filename if present */
×
1604
    stream_to_free = fopen(msBuildPath(szPath, map->mappath, filename), "w");
×
1605
    if (!stream_to_free) {
×
1606
      msSetError(MS_IOERR, "(%s)", "msGMLWriteQuery()", filename);
×
1607
      return (MS_FAILURE);
×
1608
    }
1609
    stream = stream_to_free;
1610
  }
1611

1612
  msIO_fprintf(stream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
33✔
1613
  msOWSPrintValidateMetadata(stream, &(map->web.metadata), namespaces,
33✔
1614
                             "rootname", OWS_NOERR, "<%s ", "msGMLOutput");
1615

1616
  msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "uri",
33✔
1617
                           OWS_NOERR, "xmlns=\"%s\"", NULL);
1618
  msIO_fprintf(stream, "\n\t xmlns:gml=\"http://www.opengis.net/gml\"");
33✔
1619
  msIO_fprintf(stream, "\n\t xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
33✔
1620
  msIO_fprintf(stream,
33✔
1621
               "\n\t xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
1622
  msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces, "schema",
33✔
1623
                           OWS_NOERR, "\n\t xsi:schemaLocation=\"%s\"", NULL);
1624
  msIO_fprintf(stream, ">\n");
33✔
1625

1626
  /* a schema *should* be required */
1627
  msOWSPrintEncodeMetadata(stream, &(map->web.metadata), namespaces,
33✔
1628
                           "description", OWS_NOERR,
1629
                           "\t<gml:description>%s</gml:description>\n", NULL);
1630

1631
  /* Look up map SRS. We need an EPSG code for GML, if not then we get null and
1632
   * we'll fall back on the layer's SRS */
1633
  msOWSGetEPSGProj(&(map->projection), NULL, namespaces, MS_TRUE, &pszMapSRS);
33✔
1634

1635
  /* step through the layers looking for query results */
1636
  for (i = 0; i < map->numlayers; i++) {
213✔
1637
    char *pszOutputSRS = NULL;
180✔
1638
    int nSRSDimension = 2;
1639
    const char *geomtype;
1640
    lp = (GET_LAYER(map, map->layerorder[i]));
180✔
1641

1642
    if (lp->resultcache &&
180✔
1643
        lp->resultcache->numresults > 0) { /* found results */
60✔
1644

1645
      reprojectionObj *reprojector = NULL;
1646

1647
      /* Determine output SRS, if map has none, then try using layer's native
1648
       * SRS */
1649
      if ((pszOutputSRS = pszMapSRS) == NULL) {
39✔
1650
        msOWSGetEPSGProj(&(lp->projection), NULL, namespaces, MS_TRUE,
×
1651
                         &pszOutputSRS);
1652
        if (pszOutputSRS == NULL) {
×
1653
          msSetError(
×
1654
              MS_WMSERR,
1655
              "No valid EPSG code in map or layer projection for GML output",
1656
              "msGMLWriteQuery()");
1657
          continue; /* No EPSG code, cannot output this layer */
×
1658
        }
1659
      }
1660

1661
      /* start this collection (layer) */
1662
      /* if no layer name provided fall back on the layer name + "_layer" */
1663
      value = (char *)msSmallMalloc(strlen(lp->name) + 7);
39✔
1664
      sprintf(value, "%s_layer", lp->name);
39✔
1665
      msOWSPrintValidateMetadata(stream, &(lp->metadata), namespaces,
39✔
1666
                                 "layername", OWS_NOERR, "\t<%s>\n", value);
1667
      msFree(value);
39✔
1668

1669
      value = (char *)msOWSLookupMetadata(&(lp->metadata), "OM", "title");
39✔
1670
      if (value) {
39✔
1671
        msOWSPrintEncodeMetadata(stream, &(lp->metadata), namespaces, "title",
19✔
1672
                                 OWS_NOERR, "\t<gml:name>%s</gml:name>\n",
1673
                                 value);
1674
      }
1675

1676
      geomtype = msOWSLookupMetadata(&(lp->metadata), "OFG", "geomtype");
39✔
1677
      if (geomtype != NULL && (strstr(geomtype, "25d") != NULL ||
39✔
1678
                               strstr(geomtype, "25D") != NULL)) {
×
1679
        nSRSDimension = 3;
1680
      }
1681

1682
      /* populate item and group metadata structures */
1683
      itemList = msGMLGetItems(lp, namespaces);
39✔
1684
      constantList = msGMLGetConstants(lp, namespaces);
39✔
1685
      groupList = msGMLGetGroups(lp, namespaces);
39✔
1686
      geometryList = msGMLGetGeometries(lp, namespaces, MS_FALSE);
39✔
1687
      if (itemList == NULL || constantList == NULL || groupList == NULL ||
39✔
1688
          geometryList == NULL) {
39✔
1689
        msSetError(MS_MISCERR,
×
1690
                   "Unable to populate item and group metadata structures",
1691
                   "msGMLWriteQuery()");
1692
        if (stream_to_free != NULL)
×
1693
          fclose(stream_to_free);
×
1694
        return MS_FAILURE;
×
1695
      }
1696

1697
      if (pszOutputSRS == pszMapSRS &&
78✔
1698
          msProjectionsDiffer(&(lp->projection), &(map->projection))) {
39✔
1699
        reprojector =
1700
            msProjectCreateReprojector(&(lp->projection), &(map->projection));
27✔
1701
        if (reprojector == NULL) {
27✔
1702
          msGMLFreeGroups(groupList);
×
1703
          msGMLFreeConstants(constantList);
×
1704
          msGMLFreeItems(itemList);
×
1705
          msGMLFreeGeometries(geometryList);
×
1706
          msFree(pszOutputSRS);
×
1707
          if (stream_to_free != NULL)
×
1708
            fclose(stream_to_free);
×
1709
          return MS_FAILURE;
×
1710
        }
1711
      }
1712

1713
      for (j = 0; j < lp->resultcache->numresults; j++) {
100✔
1714
        status = msLayerGetShape(lp, &shape, &(lp->resultcache->results[j]));
61✔
1715
        if (status != MS_SUCCESS) {
61✔
1716
          msGMLFreeGroups(groupList);
×
1717
          msGMLFreeConstants(constantList);
×
1718
          msGMLFreeItems(itemList);
×
1719
          msGMLFreeGeometries(geometryList);
×
1720
          msProjectDestroyReprojector(reprojector);
×
1721
          msFree(pszOutputSRS);
×
1722
          if (stream_to_free != NULL)
×
1723
            fclose(stream_to_free);
×
1724
          return MS_FAILURE;
×
1725
        }
1726

1727
        /* project the shape into the map projection (if necessary), note that
1728
         * this projects the bounds as well */
1729
        if (reprojector) {
61✔
1730
          status = msProjectShapeEx(reprojector, &shape);
47✔
1731
          if (status != MS_SUCCESS) {
47✔
1732
            msIO_fprintf(stream,
×
1733
                         "<!-- Warning: Failed to reproject shape: %s -->\n",
1734
                         msGetErrorString(","));
1735
            msFreeShape(&shape);
×
1736
            continue;
×
1737
          }
1738
        }
1739

1740
        /* start this feature */
1741
        /* specify a feature name, if nothing provided fall back on the layer
1742
         * name + "_feature" */
1743
        value = (char *)msSmallMalloc(strlen(lp->name) + 9);
61✔
1744
        sprintf(value, "%s_feature", lp->name);
61✔
1745
        msOWSPrintValidateMetadata(stream, &(lp->metadata), namespaces,
61✔
1746
                                   "featurename", OWS_NOERR, "\t\t<%s>\n",
1747
                                   value);
1748
        msFree(value);
61✔
1749

1750
        /* Write the feature geometry and bounding box unless 'none' was
1751
         * requested. */
1752
        /* Default to bbox only if nothing specified and output full geometry
1753
         * only if explicitly requested */
1754
        if (!(geometryList && geometryList->numgeometries == 1 &&
61✔
1755
              strcasecmp(geometryList->geometries[0].name, "none") == 0)) {
×
1756
          gmlWriteBounds(stream, OWS_GML2, &(shape.bounds), pszOutputSRS,
61✔
1757
                         "\t\t\t", "gml");
1758
          if (geometryList && geometryList->numgeometries > 0)
61✔
1759
            gmlWriteGeometry(stream, geometryList, OWS_GML2, &(shape),
×
1760
                             pszOutputSRS, NULL, "\t\t\t", "", nSRSDimension,
1761
                             6);
1762
        }
1763

1764
        /* write any item/values */
1765
        for (k = 0; k < itemList->numitems; k++) {
736✔
1766
          item = &(itemList->items[k]);
675✔
1767
          if (msItemInGroups(item->name, groupList) == MS_FALSE)
675✔
1768
            msGMLWriteItem(stream, item, shape.values[k], NULL, "\t\t\t",
675✔
1769
                           OWS_GML2, NULL);
1770
        }
1771

1772
        /* write any constants */
1773
        for (k = 0; k < constantList->numconstants; k++) {
61✔
1774
          constant = &(constantList->constants[k]);
×
1775
          if (msItemInGroups(constant->name, groupList) == MS_FALSE)
×
1776
            msGMLWriteConstant(stream, constant, NULL, "\t\t\t");
×
1777
        }
1778

1779
        /* write any groups */
1780
        for (k = 0; k < groupList->numgroups; k++)
61✔
1781
          msGMLWriteGroup(stream, &(groupList->groups[k]), &shape, itemList,
×
1782
                          constantList, NULL, "\t\t\t", OWS_GML2, NULL);
1783

1784
        /* end this feature */
1785
        /* specify a feature name if nothing provided */
1786
        /* fall back on the layer name + "Feature" */
1787
        value = (char *)msSmallMalloc(strlen(lp->name) + 9);
61✔
1788
        sprintf(value, "%s_feature", lp->name);
61✔
1789
        msOWSPrintValidateMetadata(stream, &(lp->metadata), namespaces,
61✔
1790
                                   "featurename", OWS_NOERR, "\t\t</%s>\n",
1791
                                   value);
1792
        msFree(value);
61✔
1793

1794
        msFreeShape(&shape); /* init too */
61✔
1795
      }
1796

1797
      msProjectDestroyReprojector(reprojector);
39✔
1798

1799
      /* end this collection (layer) */
1800
      /* if no layer name provided fall back on the layer name + "_layer" */
1801
      value = (char *)msSmallMalloc(strlen(lp->name) + 7);
39✔
1802
      sprintf(value, "%s_layer", lp->name);
39✔
1803
      msOWSPrintValidateMetadata(stream, &(lp->metadata), namespaces,
39✔
1804
                                 "layername", OWS_NOERR, "\t</%s>\n", value);
1805
      msFree(value);
39✔
1806

1807
      msGMLFreeGroups(groupList);
39✔
1808
      msGMLFreeConstants(constantList);
39✔
1809
      msGMLFreeItems(itemList);
39✔
1810
      msGMLFreeGeometries(geometryList);
39✔
1811

1812
      /* msLayerClose(lp); */
1813
    }
1814
    if (pszOutputSRS != pszMapSRS) {
180✔
1815
      msFree(pszOutputSRS);
141✔
1816
    }
1817
  } /* next layer */
1818

1819
  /* end this document */
1820
  msOWSPrintValidateMetadata(stream, &(map->web.metadata), namespaces,
33✔
1821
                             "rootname", OWS_NOERR, "</%s>\n", "msGMLOutput");
1822

1823
  if (stream_to_free != NULL)
33✔
1824
    fclose(stream_to_free);
×
1825
  msFree(pszMapSRS);
33✔
1826

1827
  return (MS_SUCCESS);
33✔
1828

1829
#else /* Stub for mapscript */
1830
  msSetError(MS_MISCERR, "WMS server support not enabled", "msGMLWriteQuery()");
1831
  return MS_FAILURE;
1832
#endif
1833
}
1834

1835
#ifdef USE_WFS_SVR
1836
void msGMLWriteWFSBounds(mapObj *map, FILE *stream, const char *tab,
478✔
1837
                         OWSGMLVersion outputformat, int nWFSVersion,
1838
                         int bUseURN) {
1839
  rectObj resultBounds = {-1.0, -1.0, -1.0, -1.0};
478✔
1840

1841
  /*add a check to see if the map projection is set to be north-east*/
1842
  int bSwapAxis = msIsAxisInvertedProj(&(map->projection));
478✔
1843

1844
  /* Need to start with BBOX of the whole resultset */
1845
  if (msGetQueryResultBounds(map, &resultBounds) > 0) {
478✔
1846
    char *srs = NULL;
426✔
1847
    if (bSwapAxis) {
426✔
1848
      double tmp;
1849

1850
      tmp = resultBounds.minx;
146✔
1851
      resultBounds.minx = resultBounds.miny;
146✔
1852
      resultBounds.miny = tmp;
146✔
1853

1854
      tmp = resultBounds.maxx;
146✔
1855
      resultBounds.maxx = resultBounds.maxy;
146✔
1856
      resultBounds.maxy = tmp;
146✔
1857
    }
1858
    if (bUseURN) {
426✔
1859
      srs = msOWSGetProjURN(&(map->projection), NULL, "FGO", MS_TRUE);
156✔
1860
      if (!srs)
156✔
1861
        srs = msOWSGetProjURN(&(map->projection), &(map->web.metadata), "FGO",
×
1862
                              MS_TRUE);
1863
    } else {
1864
      msOWSGetEPSGProj(&(map->projection), NULL, "FGO", MS_TRUE, &srs);
270✔
1865
      if (!srs)
270✔
1866
        msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "FGO",
×
1867
                         MS_TRUE, &srs);
1868
    }
1869

1870
    gmlWriteBounds(stream, outputformat, &resultBounds, srs, tab,
696✔
1871
                   (nWFSVersion == OWS_2_0_0) ? "wfs" : "gml");
1872
    msFree(srs);
426✔
1873
  }
1874
}
478✔
1875

1876
#endif
1877

1878
/*
1879
** msGMLWriteWFSQuery()
1880
**
1881
** Similar to msGMLWriteQuery() but tuned for use with WFS
1882
*/
1883
int msGMLWriteWFSQuery(mapObj *map, FILE *stream,
478✔
1884
                       const char *default_namespace_prefix,
1885
                       OWSGMLVersion outputformat, int nWFSVersion, int bUseURN,
1886
                       int bGetPropertyValueRequest) {
1887
#ifdef USE_WFS_SVR
1888
  int status;
1889
  int i, j, k;
1890
  layerObj *lp = NULL;
1891
  shapeObj shape;
1892

1893
  gmlGroupListObj *groupList = NULL;
1894
  gmlItemListObj *itemList = NULL;
1895
  gmlConstantListObj *constantList = NULL;
1896
  gmlGeometryListObj *geometryList = NULL;
1897
  gmlItemObj *item = NULL;
1898
  gmlConstantObj *constant = NULL;
1899

1900
  const char *namespace_prefix = NULL;
1901
  int bSwapAxis;
1902

1903
  msInitShape(&shape);
478✔
1904

1905
  /*add a check to see if the map projection is set to be north-east*/
1906
  bSwapAxis = msIsAxisInvertedProj(&(map->projection));
478✔
1907

1908
  /* Need to start with BBOX of the whole resultset */
1909
  if (!bGetPropertyValueRequest) {
478✔
1910
    msGMLWriteWFSBounds(map, stream, "      ", outputformat, nWFSVersion,
464✔
1911
                        bUseURN);
1912
  }
1913
  /* step through the layers looking for query results */
1914
  for (i = 0; i < map->numlayers; i++) {
2,456✔
1915

1916
    lp = GET_LAYER(map, map->layerorder[i]);
1,978✔
1917

1918
    if (lp->resultcache &&
1,978✔
1919
        lp->resultcache->numresults > 0) { /* found results */
500✔
1920
      char *layerName;
1921
      const char *value;
1922
      int featureIdIndex = -1; /* no feature id */
1923
      char *srs = NULL;
446✔
1924
      int bOutputGMLIdOnly = MS_FALSE;
1925
      int nSRSDimension = 2;
1926
      const char *geomtype;
1927
      reprojectionObj *reprojector = NULL;
1928
      int geometry_precision = 6;
1929

1930
      /* setup namespace, a layer can override the default */
1931
      namespace_prefix =
1932
          msOWSLookupMetadata(&(lp->metadata), "OFG", "namespace_prefix");
446✔
1933
      if (!namespace_prefix)
446✔
1934
        namespace_prefix = default_namespace_prefix;
1935

1936
      geomtype = msOWSLookupMetadata(&(lp->metadata), "OFG", "geomtype");
446✔
1937
      if (geomtype != NULL && (strstr(geomtype, "25d") != NULL ||
446✔
1938
                               strstr(geomtype, "25D") != NULL)) {
2✔
1939
        nSRSDimension = 3;
1940
      }
1941

1942
      value = msOWSLookupMetadata(&(lp->metadata), "OFG", "featureid");
446✔
1943
      if (value) { /* find the featureid amongst the items for this layer */
446✔
1944
        for (j = 0; j < lp->numitems; j++) {
1,004✔
1945
          if (strcasecmp(lp->items[j], value) == 0) { /* found it */
929✔
1946
            featureIdIndex = j;
1947
            break;
1948
          }
1949
        }
1950

1951
        /* Produce a warning if a featureid was set but the corresponding item
1952
         * is not found. */
1953
        if (featureIdIndex == -1)
280✔
1954
          msIO_fprintf(stream,
75✔
1955
                       "<!-- WARNING: FeatureId item '%s' not found in "
1956
                       "typename '%s'. -->\n",
1957
                       value, lp->name);
1958
      } else if (outputformat == OWS_GML32)
166✔
1959
        msIO_fprintf(stream,
11✔
1960
                     "<!-- WARNING: No featureid defined for typename '%s'. "
1961
                     "Output will not validate. -->\n",
1962
                     lp->name);
1963

1964
      /* populate item and group metadata structures */
1965
      itemList = msGMLGetItems(lp, "G");
446✔
1966
      constantList = msGMLGetConstants(lp, "G");
446✔
1967
      groupList = msGMLGetGroups(lp, "G");
446✔
1968
      geometryList = msGMLGetGeometries(lp, "GFO", MS_FALSE);
446✔
1969
      if (itemList == NULL || constantList == NULL || groupList == NULL ||
446✔
1970
          geometryList == NULL) {
446✔
1971
        msSetError(MS_MISCERR,
×
1972
                   "Unable to populate item and group metadata structures",
1973
                   "msGMLWriteWFSQuery()");
1974
        return MS_FAILURE;
×
1975
      }
1976

1977
      if (bGetPropertyValueRequest) {
446✔
1978
        const char *value =
1979
            msOWSLookupMetadata(&(lp->metadata), "G", "include_items");
14✔
1980
        if (value != NULL && strcmp(value, "@gml:id") == 0)
14✔
1981
          bOutputGMLIdOnly = MS_TRUE;
1982
      }
1983

1984
      if (namespace_prefix) {
446✔
1985
        layerName = (char *)msSmallMalloc(strlen(namespace_prefix) +
446✔
1986
                                          strlen(lp->name) + 2);
446✔
1987
        sprintf(layerName, "%s:%s", namespace_prefix, lp->name);
446✔
1988
      } else {
1989
        layerName = msStrdup(lp->name);
×
1990
      }
1991

1992
      if (bUseURN) {
446✔
1993
        srs = msOWSGetProjURN(&(map->projection), NULL, "FGO", MS_TRUE);
156✔
1994
        if (!srs)
156✔
1995
          srs = msOWSGetProjURN(&(map->projection), &(map->web.metadata), "FGO",
×
1996
                                MS_TRUE);
1997
        if (!srs)
156✔
1998
          srs = msOWSGetProjURN(&(lp->projection), &(lp->metadata), "FGO",
×
1999
                                MS_TRUE);
2000
      } else {
2001
        msOWSGetEPSGProj(&(map->projection), NULL, "FGO", MS_TRUE, &srs);
290✔
2002
        if (!srs)
290✔
2003
          msOWSGetEPSGProj(&(map->projection), &(map->web.metadata), "FGO",
×
2004
                           MS_TRUE, &srs);
2005
        if (!srs)
290✔
2006
          msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "FGO", MS_TRUE,
×
2007
                           &srs);
2008
      }
2009

2010
      if (msProjectionsDiffer(&(lp->projection), &(map->projection))) {
446✔
2011
        reprojector =
2012
            msProjectCreateReprojector(&(lp->projection), &(map->projection));
314✔
2013
        if (reprojector == NULL) {
314✔
2014
          msGMLFreeGroups(groupList);
×
2015
          msGMLFreeConstants(constantList);
×
2016
          msGMLFreeItems(itemList);
×
2017
          msGMLFreeGeometries(geometryList);
×
2018
          msFree(layerName);
×
2019
          msFree(srs);
×
2020
          return MS_FAILURE;
×
2021
        }
2022
      }
2023

2024
      for (j = 0; j < lp->resultcache->numresults; j++) {
3,564✔
2025
        char *pszFID;
2026

2027
        if (lp->resultcache->results[j].shape) {
3,118✔
2028
          /* msDebug("Using cached shape %ld\n",
2029
           * lp->resultcache->results[j].shapeindex); */
2030
          msCopyShape(lp->resultcache->results[j].shape, &shape);
3✔
2031
        } else {
2032
          status = msLayerGetShape(lp, &shape, &(lp->resultcache->results[j]));
3,115✔
2033
          if (status != MS_SUCCESS) {
3,115✔
2034
            msGMLFreeGroups(groupList);
×
2035
            msGMLFreeConstants(constantList);
×
2036
            msGMLFreeItems(itemList);
×
2037
            msGMLFreeGeometries(geometryList);
×
2038
            msFree(layerName);
×
2039
            msProjectDestroyReprojector(reprojector);
×
2040
            msFree(srs);
×
2041
            return (status);
×
2042
          }
2043
        }
2044

2045
        /* project the shape into the map projection (if necessary), note that
2046
         * this projects the bounds as well */
2047
        if (reprojector)
3,118✔
2048
          msProjectShapeEx(reprojector, &shape);
2,068✔
2049

2050
        if (featureIdIndex != -1) {
3,118✔
2051
          pszFID = (char *)msSmallMalloc(
1,770✔
2052
              strlen(lp->name) + 1 + strlen(shape.values[featureIdIndex]) + 1);
1,770✔
2053
          sprintf(pszFID, "%s.%s", lp->name, shape.values[featureIdIndex]);
1,770✔
2054
        } else
2055
          pszFID = msStrdup("");
1,348✔
2056

2057
        if (bOutputGMLIdOnly) {
3,118✔
2058
          msIO_fprintf(stream, "    <wfs:member>%s</wfs:member>\n", pszFID);
42✔
2059
          msFree(pszFID);
42✔
2060
          msFreeShape(&shape); /* init too */
42✔
2061
          continue;
42✔
2062
        }
2063

2064
        /*
2065
        ** start this feature
2066
        */
2067
        if (nWFSVersion == OWS_2_0_0)
3,076✔
2068
          msIO_fprintf(stream, "    <wfs:member>\n");
1,321✔
2069
        else
2070
          msIO_fprintf(stream, "    <gml:featureMember>\n");
1,755✔
2071
        if (msIsXMLTagValid(layerName) == MS_FALSE)
3,076✔
2072
          msIO_fprintf(stream,
×
2073
                       "<!-- WARNING: The value '%s' is not valid in a XML tag "
2074
                       "context. -->\n",
2075
                       layerName);
2076
        if (featureIdIndex != -1) {
3,076✔
2077
          if (!bGetPropertyValueRequest) {
1,728✔
2078
            if (outputformat == OWS_GML2)
1,532✔
2079
              msIO_fprintf(stream, "      <%s fid=\"%s\">\n", layerName,
386✔
2080
                           pszFID);
2081
            else /* OWS_GML3 or OWS_GML32 */
2082
              msIO_fprintf(stream, "      <%s gml:id=\"%s\">\n", layerName,
1,146✔
2083
                           pszFID);
2084
          }
2085
        } else {
2086
          if (!bGetPropertyValueRequest)
1,348✔
2087
            msIO_fprintf(stream, "      <%s>\n", layerName);
1,348✔
2088
        }
2089

2090
        if (bSwapAxis)
3,076✔
2091
          msAxisSwapShape(&shape);
1,185✔
2092

2093
        /* write the feature geometry and bounding box */
2094
        if (!(geometryList && geometryList->numgeometries == 1 &&
3,076✔
2095
              strcasecmp(geometryList->geometries[0].name, "none") == 0)) {
1,420✔
2096
          if (!bGetPropertyValueRequest)
2,545✔
2097
            gmlWriteBounds(stream, outputformat, &(shape.bounds), srs,
2,517✔
2098
                           "        ", "gml");
2099

2100
          if (msOWSLookupMetadata(&(lp->metadata), "F", "geometry_precision")) {
2,545✔
2101
            geometry_precision = atoi(msOWSLookupMetadata(
1✔
2102
                &(lp->metadata), "F", "geometry_precision"));
2103
          } else if (msOWSLookupMetadata(&map->web.metadata, "F",
2,544✔
2104
                                         "geometry_precision")) {
2105
            geometry_precision = atoi(msOWSLookupMetadata(
4✔
2106
                &map->web.metadata, "F", "geometry_precision"));
2107
          }
2108

2109
          gmlWriteGeometry(stream, geometryList, outputformat, &(shape), srs,
2,545✔
2110
                           namespace_prefix, "        ", pszFID, nSRSDimension,
2111
                           geometry_precision);
2112
        }
2113

2114
        /* write any item/values */
2115
        for (k = 0; k < itemList->numitems; k++) {
31,323✔
2116
          item = &(itemList->items[k]);
28,247✔
2117
          if (msItemInGroups(item->name, groupList) == MS_FALSE)
28,247✔
2118
            msGMLWriteItem(stream, item, shape.values[k], namespace_prefix,
27,428✔
2119
                           "        ", outputformat, pszFID);
2120
        }
2121

2122
        /* write any constants */
2123
        for (k = 0; k < constantList->numconstants; k++) {
3,076✔
2124
          constant = &(constantList->constants[k]);
×
2125
          if (msItemInGroups(constant->name, groupList) == MS_FALSE)
×
2126
            msGMLWriteConstant(stream, constant, namespace_prefix, "        ");
×
2127
        }
2128

2129
        /* write any groups */
2130
        for (k = 0; k < groupList->numgroups; k++)
3,349✔
2131
          msGMLWriteGroup(stream, &(groupList->groups[k]), &shape, itemList,
273✔
2132
                          constantList, namespace_prefix, "        ",
2133
                          outputformat, pszFID);
2134

2135
        if (!bGetPropertyValueRequest)
3,076✔
2136
          /* end this feature */
2137
          msIO_fprintf(stream, "      </%s>\n", layerName);
2,880✔
2138

2139
        if (nWFSVersion == OWS_2_0_0)
3,076✔
2140
          msIO_fprintf(stream, "    </wfs:member>\n");
1,321✔
2141
        else
2142
          msIO_fprintf(stream, "    </gml:featureMember>\n");
1,755✔
2143

2144
        msFree(pszFID);
3,076✔
2145
        pszFID = NULL;
2146
        msFreeShape(&shape); /* init too */
3,076✔
2147
      }
2148

2149
      msProjectDestroyReprojector(reprojector);
446✔
2150

2151
      msFree(srs);
446✔
2152

2153
      /* done with this layer, do a little clean-up */
2154
      msFree(layerName);
446✔
2155

2156
      msGMLFreeGroups(groupList);
446✔
2157
      msGMLFreeConstants(constantList);
446✔
2158
      msGMLFreeItems(itemList);
446✔
2159
      msGMLFreeGeometries(geometryList);
446✔
2160

2161
      /* msLayerClose(lp); */
2162
    }
2163

2164
  } /* next layer */
2165

2166
  return (MS_SUCCESS);
2167

2168
#else  /* Stub for mapscript */
2169
  (void)map;
2170
  (void)stream;
2171
  (void)default_namespace_prefix;
2172
  (void)outputformat;
2173
  (void)nWFSVersion;
2174
  (void)bUseURN;
2175
  (void)bGetPropertyValueRequest;
2176
  msSetError(MS_MISCERR, "WFS server support not enabled",
2177
             "msGMLWriteWFSQuery()");
2178
  return MS_FAILURE;
2179
#endif /* USE_WFS_SVR */
2180
}
2181

2182
#ifdef USE_LIBXML2
2183

2184
/**
2185
 * msGML3BoundedBy()
2186
 *
2187
 * returns an object of BoundedBy as per GML 3
2188
 *
2189
 * @param xmlNsPtr psNs the namespace object
2190
 * @param minx minx
2191
 * @param miny miny
2192
 * @param maxx maxx
2193
 * @param mayy mayy
2194
 * @param psEpsg epsg code
2195
 * @param dimension number of dimensions
2196
 *
2197
 * @return psNode xmlNodePtr of XML construct
2198
 *
2199
 */
2200

2201
xmlNodePtr msGML3BoundedBy(xmlNsPtr psNs, double minx, double miny, double maxx,
38✔
2202
                           double maxy, const char *psEpsg) {
2203
  xmlNodePtr psNode = NULL, psSubNode = NULL;
2204
  char *pszTmp = NULL;
2205
  char *pszTmp2 = NULL;
2206
  char *pszEpsg = NULL;
2207

2208
  psNode = xmlNewNode(psNs, BAD_CAST "boundedBy");
38✔
2209
  psSubNode = xmlNewChild(psNode, NULL, BAD_CAST "Envelope", NULL);
38✔
2210

2211
  if (psEpsg) {
38✔
2212
    const size_t bufferSize = strlen(psEpsg) + 1;
38✔
2213
    pszEpsg = (char *)msSmallMalloc(bufferSize);
38✔
2214
    snprintf(pszEpsg, bufferSize, "%s", psEpsg);
2215
    msStringToLower(pszEpsg);
38✔
2216
    pszTmp = msStringConcatenate(pszTmp, "urn:ogc:crs:");
38✔
2217
    pszTmp = msStringConcatenate(pszTmp, pszEpsg);
38✔
2218
    xmlNewProp(psSubNode, BAD_CAST "srsName", BAD_CAST pszTmp);
38✔
2219
    free(pszEpsg);
38✔
2220
    free(pszTmp);
38✔
2221
    pszTmp = msIntToString(2);
38✔
2222
    xmlNewProp(psSubNode, BAD_CAST "srsDimension", BAD_CAST pszTmp);
38✔
2223
    free(pszTmp);
38✔
2224
  }
2225

2226
  pszTmp = msDoubleToString(minx, MS_TRUE);
38✔
2227
  pszTmp = msStringConcatenate(pszTmp, " ");
38✔
2228
  pszTmp2 = msDoubleToString(miny, MS_TRUE);
38✔
2229
  pszTmp = msStringConcatenate(pszTmp, pszTmp2);
38✔
2230
  xmlNewChild(psSubNode, NULL, BAD_CAST "lowerCorner", BAD_CAST pszTmp);
38✔
2231
  free(pszTmp);
38✔
2232
  free(pszTmp2);
38✔
2233

2234
  pszTmp = msDoubleToString(maxx, MS_TRUE);
38✔
2235
  pszTmp = msStringConcatenate(pszTmp, " ");
38✔
2236
  pszTmp2 = msDoubleToString(maxy, MS_TRUE);
38✔
2237
  pszTmp = msStringConcatenate(pszTmp, pszTmp2);
38✔
2238
  xmlNewChild(psSubNode, NULL, BAD_CAST "upperCorner", BAD_CAST pszTmp);
38✔
2239
  free(pszTmp);
38✔
2240
  free(pszTmp2);
38✔
2241
  return psNode;
38✔
2242
}
2243

2244
/**
2245
 *msGML3Point()
2246
 *
2247
 * returns an object of Point as per GML 3
2248
 *
2249
 * @param xmlNsPtr psNs the gml namespace object
2250
 * @param pszSrsName EPSG code of geometry
2251
 * @param id
2252
 * @param x x coordinate
2253
 * @param y y coordinate
2254
 * @param z z coordinate
2255
 *
2256
 * @return psNode xmlNodePtr of XML construct
2257
 *
2258
 */
2259

2260
xmlNodePtr msGML3Point(xmlNsPtr psNs, const char *psSrsName, const char *id,
24✔
2261
                       double x, double y) {
2262

2263
  xmlNodePtr psNode = xmlNewNode(psNs, BAD_CAST "Point");
24✔
2264

2265
  if (id) {
24✔
2266
    xmlNewNsProp(psNode, psNs, BAD_CAST "id", BAD_CAST id);
×
2267
  }
2268

2269
  if (psSrsName) {
24✔
2270
    const size_t bufferSize = strlen(psSrsName) + 1;
24✔
2271
    char *pszSrsName = (char *)msSmallMalloc(bufferSize);
24✔
2272
    snprintf(pszSrsName, bufferSize, "%s", psSrsName);
2273
    msStringToLower(pszSrsName);
24✔
2274
    char *pszTmp = NULL;
2275
    pszTmp = msStringConcatenate(pszTmp, "urn:ogc:crs:");
24✔
2276
    pszTmp = msStringConcatenate(pszTmp, pszSrsName);
24✔
2277
    xmlNewProp(psNode, BAD_CAST "srsName", BAD_CAST pszTmp);
24✔
2278
    free(pszSrsName);
24✔
2279
    free(pszTmp);
24✔
2280
    const int dimension = 2;
2281
    pszTmp = msIntToString(dimension);
24✔
2282
    xmlNewProp(psNode, BAD_CAST "srsDimension", BAD_CAST pszTmp);
24✔
2283
    free(pszTmp);
24✔
2284
  }
2285

2286
  char *pszTmp = msDoubleToString(x, MS_TRUE);
24✔
2287
  pszTmp = msStringConcatenate(pszTmp, " ");
24✔
2288
  char *pszTmp2 = msDoubleToString(y, MS_TRUE);
24✔
2289
  pszTmp = msStringConcatenate(pszTmp, pszTmp2);
24✔
2290
  xmlNewChild(psNode, NULL, BAD_CAST "pos", BAD_CAST pszTmp);
24✔
2291

2292
  free(pszTmp);
24✔
2293
  free(pszTmp2);
24✔
2294
  return psNode;
24✔
2295
}
2296

2297
/**
2298
 * msGML3TimePeriod()
2299
 *
2300
 * returns an object of TimePeriod as per GML 3
2301
 *
2302
 * @param xmlNsPtr psNs the gml namespace object
2303
 * @param pszStart start time
2304
 * @param pszEnd end time
2305
 *
2306
 * @return psNode xmlNodePtr of XML construct
2307
 *
2308
 */
2309

2310
xmlNodePtr msGML3TimePeriod(xmlNsPtr psNs, char *pszStart, char *pszEnd) {
7✔
2311
  xmlNodePtr psNode = NULL;
2312

2313
  psNode = xmlNewNode(psNs, BAD_CAST "TimePeriod");
7✔
2314
  xmlNewChild(psNode, NULL, BAD_CAST "beginPosition", BAD_CAST pszStart);
7✔
2315
  if (pszEnd)
7✔
2316
    xmlNewChild(psNode, NULL, BAD_CAST "endPosition", BAD_CAST pszEnd);
7✔
2317
  else {
2318
    xmlNewChild(psNode, NULL, BAD_CAST "endPosition", NULL);
×
2319
    xmlNewProp(psNode, BAD_CAST "indeterminatePosition", BAD_CAST "now");
×
2320
  }
2321
  return psNode;
7✔
2322
}
2323

2324
/**
2325
 * msGML3TimeInstant()
2326
 *
2327
 * returns an object of TimeInstant as per GML 3
2328
 *
2329
 * @param xmlNsPtr psNs the gml namespace object
2330
 * @param timeInstant time instant
2331
 *
2332
 * @return psNode xmlNodePtr of XML construct
2333
 *
2334
 */
2335

2336
xmlNodePtr msGML3TimeInstant(xmlNsPtr psNs, char *pszTime) {
24✔
2337
  xmlNodePtr psNode = NULL;
2338

2339
  psNode = xmlNewNode(psNs, BAD_CAST "TimeInstant");
24✔
2340
  xmlNewChild(psNode, NULL, BAD_CAST "timePosition", BAD_CAST pszTime);
24✔
2341
  return psNode;
24✔
2342
}
2343

2344
#endif /* USE_LIBXML2 */
2345

2346
/************************************************************************/
2347
/*      The following functions are enabled in all cases, even if       */
2348
/*      WMS and WFS are not available.                                  */
2349
/************************************************************************/
2350

2351
gmlItemListObj *msGMLGetItems(layerObj *layer,
1,294✔
2352
                              const char *metadata_namespaces) {
2353
  int i, j;
2354

2355
  char **xmlitems = NULL;
2356
  int numxmlitems = 0;
1,294✔
2357

2358
  char **incitems = NULL;
2359
  int numincitems = 0;
1,294✔
2360

2361
  char **excitems = NULL;
2362
  int numexcitems = 0;
1,294✔
2363

2364
  char **optionalitems = NULL;
2365
  int numoptionalitems = 0;
1,294✔
2366

2367
  char **mandatoryitems = NULL;
2368
  int nummandatoryitems = 0;
1,294✔
2369

2370
  char **defaultitems = NULL;
2371
  int numdefaultitems = 0;
1,294✔
2372

2373
  const char *value = NULL;
2374
  char tag[64];
2375

2376
  gmlItemListObj *itemList = NULL;
2377
  gmlItemObj *item = NULL;
2378

2379
  /* get a list of items that might be included in output */
2380
  if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
1,294✔
2381
                                   "include_items")) != NULL)
2382
    incitems = msStringSplit(value, ',', &numincitems);
1,072✔
2383

2384
  /* get a list of items that should be excluded in output */
2385
  if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
1,294✔
2386
                                   "exclude_items")) != NULL)
2387
    excitems = msStringSplit(value, ',', &numexcitems);
191✔
2388

2389
  /* get a list of items that should not be XML encoded */
2390
  if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
1,294✔
2391
                                   "xml_items")) != NULL)
2392
    xmlitems = msStringSplit(value, ',', &numxmlitems);
×
2393

2394
  /* get a list of items that should be indicated as optional in
2395
   * DescribeFeatureType */
2396
  if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
1,294✔
2397
                                   "optional_items")) != NULL)
2398
    optionalitems = msStringSplit(value, ',', &numoptionalitems);
81✔
2399

2400
  /* get a list of items that should be indicated as mandatory in
2401
   * DescribeFeatureType */
2402
  if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
1,294✔
2403
                                   "mandatory_items")) != NULL)
2404
    mandatoryitems = msStringSplit(value, ',', &nummandatoryitems);
62✔
2405

2406
  /* get a list of items that should be presented by default in GetFeature */
2407
  if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
1,294✔
2408
                                   "default_items")) != NULL)
2409
    defaultitems = msStringSplit(value, ',', &numdefaultitems);
169✔
2410

2411
  /* allocate memory and iinitialize the item collection */
2412
  itemList = (gmlItemListObj *)malloc(sizeof(gmlItemListObj));
1,294✔
2413
  if (itemList == NULL) {
1,294✔
2414
    msSetError(MS_MEMERR, "Error allocating a collection GML item structures.",
×
2415
               "msGMLGetItems()");
2416
    return NULL;
×
2417
  }
2418

2419
  itemList->numitems = layer->numitems;
1,294✔
2420
  itemList->items =
1,294✔
2421
      (gmlItemObj *)malloc(sizeof(gmlItemObj) * itemList->numitems);
1,294✔
2422
  if (!itemList->items) {
1,294✔
2423
    msSetError(MS_MEMERR, "Error allocating a collection GML item structures.",
×
2424
               "msGMLGetItems()");
2425
    free(itemList);
×
2426
    return NULL;
×
2427
  }
2428

2429
  for (i = 0; i < layer->numitems; i++) {
14,312✔
2430
    item = &(itemList->items[i]);
13,018✔
2431

2432
    item->name = msStrdup(layer->items[i]); /* initialize the item */
13,018✔
2433
    item->alias = NULL;
13,018✔
2434
    item->type = NULL;
13,018✔
2435
    item->template = NULL;
13,018✔
2436
    item->encode = MS_TRUE;
13,018✔
2437
    item->visible = MS_FALSE;
13,018✔
2438
    item->width = 0;
13,018✔
2439
    item->precision = 0;
13,018✔
2440
    item->outputByDefault = (numdefaultitems == 0);
13,018✔
2441
    item->minOccurs = 0;
13,018✔
2442

2443
    /* check visibility, included items first... */
2444
    if (numincitems == 1 && strcasecmp("all", incitems[0]) == 0) {
13,018✔
2445
      item->visible = MS_TRUE;
6,191✔
2446
    } else {
2447
      for (j = 0; j < numincitems; j++) {
59,069✔
2448
        if (strcasecmp(layer->items[i], incitems[j]) == 0)
52,242✔
2449
          item->visible = MS_TRUE;
3,559✔
2450
      }
2451
    }
2452

2453
    /* ...and now excluded items */
2454
    for (j = 0; j < numexcitems; j++) {
15,952✔
2455
      if (strcasecmp(layer->items[i], excitems[j]) == 0)
2,934✔
2456
        item->visible = MS_FALSE;
222✔
2457
    }
2458

2459
    /* check encoding */
2460
    for (j = 0; j < numxmlitems; j++) {
13,018✔
2461
      if (strcasecmp(layer->items[i], xmlitems[j]) == 0)
×
2462
        item->encode = MS_FALSE;
×
2463
    }
2464

2465
    /* check optional */
2466
    if (numoptionalitems == 1 && strcasecmp("all", optionalitems[0]) == 0) {
13,018✔
2467
      item->minOccurs = 0;
2468
    } else if (numoptionalitems > 0) {
12,003✔
2469
      item->minOccurs = 1;
×
2470
      for (j = 0; j < numoptionalitems; j++) {
×
2471
        if (strcasecmp(layer->items[i], optionalitems[j]) == 0)
×
2472
          item->minOccurs = 0;
×
2473
      }
2474
    }
2475

2476
    /* check mandatory */
2477
    if (nummandatoryitems == 1 && strcasecmp("all", mandatoryitems[0]) == 0) {
13,018✔
2478
      item->minOccurs = 1;
×
2479
    } else if (nummandatoryitems > 0) {
13,018✔
2480
      item->minOccurs = 0;
751✔
2481
      for (j = 0; j < nummandatoryitems; j++) {
1,502✔
2482
        if (strcasecmp(layer->items[i], mandatoryitems[j]) == 0)
751✔
2483
          item->minOccurs = 1;
62✔
2484
      }
2485
    }
2486

2487
    /* check default */
2488
    for (j = 0; j < numdefaultitems; j++) {
16,926✔
2489
      if (strcasecmp(layer->items[i], defaultitems[j]) == 0)
3,908✔
2490
        item->outputByDefault = 1;
290✔
2491
    }
2492

2493
    snprintf(tag, sizeof(tag), "%s_alias", layer->items[i]);
13,018✔
2494
    if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
13,018✔
2495
                                     tag)) != NULL)
2496
      item->alias = msStrdup(value);
177✔
2497

2498
    snprintf(tag, sizeof(tag), "%s_type", layer->items[i]);
13,018✔
2499
    if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
13,018✔
2500
                                     tag)) != NULL)
2501
      item->type = msStrdup(value);
2,328✔
2502

2503
    snprintf(tag, sizeof(tag), "%s_template", layer->items[i]);
13,018✔
2504
    if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
13,018✔
2505
                                     tag)) != NULL)
2506
      item->template = msStrdup(value);
×
2507

2508
    snprintf(tag, sizeof(tag), "%s_width", layer->items[i]);
13,018✔
2509
    if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
13,018✔
2510
                                     tag)) != NULL)
2511
      item->width = atoi(value);
1,005✔
2512

2513
    snprintf(tag, sizeof(tag), "%s_precision", layer->items[i]);
13,018✔
2514
    if ((value = msOWSLookupMetadata(&(layer->metadata), metadata_namespaces,
13,018✔
2515
                                     tag)) != NULL)
2516
      item->precision = atoi(value);
109✔
2517
  }
2518

2519
  msFreeCharArray(incitems, numincitems);
1,294✔
2520
  msFreeCharArray(excitems, numexcitems);
1,294✔
2521
  msFreeCharArray(xmlitems, numxmlitems);
1,294✔
2522
  msFreeCharArray(optionalitems, numoptionalitems);
1,294✔
2523
  msFreeCharArray(mandatoryitems, nummandatoryitems);
1,294✔
2524
  msFreeCharArray(defaultitems, numdefaultitems);
1,294✔
2525

2526
  return itemList;
1,294✔
2527
}
2528

2529
void msGMLFreeItems(gmlItemListObj *itemList) {
1,294✔
2530
  int i;
2531

2532
  if (!itemList)
1,294✔
2533
    return;
2534

2535
  for (i = 0; i < itemList->numitems; i++) {
14,312✔
2536
    msFree(itemList->items[i].name);
13,018✔
2537
    msFree(itemList->items[i].alias);
13,018✔
2538
    msFree(itemList->items[i].type);
13,018✔
2539
    msFree(itemList->items[i].template);
13,018✔
2540
  }
2541

2542
  if (itemList->items != NULL)
1,294✔
2543
    free(itemList->items);
1,294✔
2544

2545
  free(itemList);
1,294✔
2546
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc