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

geographika / mapserver / 13697752106

06 Mar 2025 11:34AM UTC coverage: 41.364% (-0.03%) from 41.392%
13697752106

push

github

geographika
Mark zip output tests as TO_FIX as output is different on each run

61755 of 149297 relevant lines covered (41.36%)

24825.13 hits per line

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

70.84
/src/mapogroutput.cpp
1
/**********************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  OGR Output (for WFS)
6
 * Author:   Frank Warmerdam (warmerdam@pobox.com)
7
 *
8
 **********************************************************************
9
 * Copyright (c) 2010, Frank Warmerdam <warmerdam@pobox.com>
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 OR
22
 * 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 <assert.h>
31
#include "mapserver.h"
32
#include "mapproject.h"
33
#include "mapthread.h"
34
#include "mapows.h"
35

36
#include "ogr_api.h"
37
#include "ogr_srs_api.h"
38
#include "cpl_conv.h"
39
#include "cpl_vsi.h"
40
#include "cpl_string.h"
41

42
#include <string>
43

44
/************************************************************************/
45
/*                   msInitDefaultOGROutputFormat()                     */
46
/************************************************************************/
47

48
int msInitDefaultOGROutputFormat(outputFormatObj *format)
338✔
49

50
{
51
  OGRSFDriverH hDriver;
52

53
  msOGRInitialize();
338✔
54

55
  /* -------------------------------------------------------------------- */
56
  /*      check that this driver exists.  Note visiting drivers should    */
57
  /*      be pretty threadsafe so don't bother acquiring the GDAL         */
58
  /*      lock.                                                           */
59
  /* -------------------------------------------------------------------- */
60
  hDriver = OGRGetDriverByName(format->driver + 4);
338✔
61
  if (hDriver == NULL) {
338✔
62
    msSetError(MS_MISCERR, "No OGR driver named `%s' available.",
1✔
63
               "msInitDefaultOGROutputFormat()", format->driver + 4);
1✔
64
    return MS_FAILURE;
1✔
65
  }
66

67
  if (!OGR_Dr_TestCapability(hDriver, ODrCCreateDataSource)) {
337✔
68
    msSetError(MS_MISCERR, "OGR `%s' driver does not support output.",
1✔
69
               "msInitDefaultOGROutputFormat()", format->driver + 4);
1✔
70
    return MS_FAILURE;
1✔
71
  }
72

73
  /* -------------------------------------------------------------------- */
74
  /*      Initialize the object.                                          */
75
  /* -------------------------------------------------------------------- */
76
  format->imagemode = MS_IMAGEMODE_FEATURE;
336✔
77
  format->renderer = MS_RENDER_WITH_OGR;
336✔
78

79
  /* perhaps we should eventually hardcode mimetypes and extensions
80
     for some formats? */
81

82
  return MS_SUCCESS;
336✔
83
}
84

85
/************************************************************************/
86
/*                        msCSLConcatenate()                            */
87
/************************************************************************/
88

89
static char **msCSLConcatenate(char **papszResult, char **papszToBeAdded) {
90
  char **papszIter = papszToBeAdded;
91
  while (papszIter && *papszIter) {
23✔
92
    papszResult = CSLAddString(papszResult, *papszIter);
9✔
93
    papszIter++;
9✔
94
  }
95
  return papszResult;
96
}
97

98
/************************************************************************/
99
/*                       msOGRRecursiveFileList()                       */
100
/*                                                                      */
101
/*      Collect a list of all files under the named directory,          */
102
/*      including those in subdirectories.                              */
103
/************************************************************************/
104

105
char **msOGRRecursiveFileList(const char *path) {
14✔
106
  char **file_list;
107
  char **result_list = NULL;
108
  int i, count, change;
109

110
  file_list = CPLReadDir(path);
14✔
111
  count = CSLCount(file_list);
14✔
112

113
  /* -------------------------------------------------------------------- */
114
  /*      Sort the file list so we always get them back in the same       */
115
  /*      order - it makes autotests more stable.                         */
116
  /* -------------------------------------------------------------------- */
117
  do {
118
    change = 0;
119
    for (i = 0; i < count - 1; i++) {
92✔
120
      if (strcasecmp(file_list[i], file_list[i + 1]) > 0) {
67✔
121
        char *temp = file_list[i];
122
        file_list[i] = file_list[i + 1];
20✔
123
        file_list[i + 1] = temp;
20✔
124
        change = 1;
125
      }
126
    }
127
  } while (change);
25✔
128

129
  /* -------------------------------------------------------------------- */
130
  /*      collect names we want and process subdirectories.               */
131
  /* -------------------------------------------------------------------- */
132
  for (i = 0; i < count; i++) {
58✔
133
    char full_filename[MS_MAXPATHLEN];
134
    VSIStatBufL sStatBuf;
135

136
    if (EQUAL(file_list[i], ".") || EQUAL(file_list[i], ".."))
44✔
137
      continue;
16✔
138

139
    strlcpy(full_filename, CPLFormFilename(path, file_list[i], NULL),
28✔
140
            sizeof(full_filename));
141

142
    if (VSIStatL(full_filename, &sStatBuf) != 0)
28✔
143
      continue;
×
144

145
    if (VSI_ISREG(sStatBuf.st_mode)) {
28✔
146
      result_list = CSLAddString(result_list, full_filename);
28✔
147
    } else if (VSI_ISDIR(sStatBuf.st_mode)) {
×
148
      char **subfiles = msOGRRecursiveFileList(full_filename);
×
149

150
      result_list = msCSLConcatenate(result_list, subfiles);
151

152
      CSLDestroy(subfiles);
×
153
    }
154
  }
155

156
  CSLDestroy(file_list);
14✔
157

158
  return result_list;
14✔
159
}
160

161
/************************************************************************/
162
/*                           msOGRCleanupDS()                           */
163
/************************************************************************/
164
static void msOGRCleanupDS(const char *datasource_name)
39✔
165

166
{
167
  char **file_list;
168
  char path[MS_MAXPATHLEN];
169
  int i;
170
  VSIStatBufL sStatBuf;
171

172
  if (VSIStatL(datasource_name, &sStatBuf) != 0)
39✔
173
    return;
5✔
174
  if (VSI_ISDIR(sStatBuf.st_mode))
34✔
175
    strlcpy(path, datasource_name, sizeof(path));
176
  else
177
    strlcpy(path, CPLGetPath(datasource_name), sizeof(path));
31✔
178

179
  file_list = CPLReadDir(path);
34✔
180

181
  for (i = 0; file_list != NULL && file_list[i] != NULL; i++) {
100✔
182
    char full_filename[MS_MAXPATHLEN];
183
    VSIStatBufL sStatBuf;
184

185
    if (EQUAL(file_list[i], ".") || EQUAL(file_list[i], ".."))
66✔
186
      continue;
18✔
187

188
    strlcpy(full_filename, CPLFormFilename(path, file_list[i], NULL),
48✔
189
            sizeof(full_filename));
190

191
    if (VSIStatL(full_filename, &sStatBuf) != 0)
48✔
192
      continue;
×
193

194
    if (VSI_ISREG(sStatBuf.st_mode)) {
48✔
195
      VSIUnlink(full_filename);
48✔
196
    } else if (VSI_ISDIR(sStatBuf.st_mode)) {
×
197
      msOGRCleanupDS(full_filename);
×
198
    }
199
  }
200

201
  CSLDestroy(file_list);
34✔
202

203
  VSIRmdir(path);
34✔
204
}
205

206
/************************************************************************/
207
/*                          msOGRSetPoints()                            */
208
/************************************************************************/
209

210
static void msOGRSetPoints(OGRGeometryH hGeom, lineObj *line,
93✔
211
                           int bWant2DOutput) {
212
  int i;
213
  if (bWant2DOutput) {
93✔
214
    for (i = 0; i < line->numpoints; i++) {
43,188✔
215
      OGR_G_SetPoint_2D(hGeom, i, line->point[i].x, line->point[i].y);
43,095✔
216
    }
217
  } else {
218
    for (i = 0; i < line->numpoints; i++) {
×
219
      OGR_G_SetPoint(hGeom, i, line->point[i].x, line->point[i].y,
×
220
                     line->point[i].z);
×
221
    }
222
  }
223
}
93✔
224

225
/************************************************************************/
226
/*                          msOGRWriteShape()                           */
227
/************************************************************************/
228

229
static int msOGRWriteShape(OGRLayerH hOGRLayer, shapeObj *shape,
158✔
230
                           gmlItemListObj *item_list, int nFirstOGRFieldIndex,
231
                           const char *pszFeatureid, bool geomTypeForced)
232

233
{
234
  OGRGeometryH hGeom = NULL;
235
  OGRFeatureH hFeat;
236
  OGRErr eErr;
237
  int i, out_field;
238
  OGRwkbGeometryType eLayerGType, eFlattenLayerGType;
239
  OGRFeatureDefnH hLayerDefn;
240
  int bWant2DOutput;
241

242
  hLayerDefn = OGR_L_GetLayerDefn(hOGRLayer);
158✔
243
  eLayerGType = OGR_FD_GetGeomType(hLayerDefn);
158✔
244
  eFlattenLayerGType = wkbFlatten(eLayerGType);
158✔
245
  bWant2DOutput = (eLayerGType == eFlattenLayerGType);
158✔
246

247
  /* -------------------------------------------------------------------- */
248
  /*      Transform point geometry.                                       */
249
  /* -------------------------------------------------------------------- */
250
  if (shape->type == MS_SHAPE_POINT) {
158✔
251
    OGRGeometryH hMP = NULL;
252
    int j;
253

254
    if (shape->numlines == 1 && shape->line[0].numpoints > 1) {
68✔
255
      hGeom = OGR_G_CreateGeometry(wkbMultiPoint);
×
256
      for (j = 0; j < shape->line[0].numpoints; j++) {
×
257
        OGRGeometryH hPoint = OGR_G_CreateGeometry(wkbPoint);
×
258
        if (bWant2DOutput) {
×
259
          OGR_G_SetPoint_2D(hPoint, 0, shape->line[0].point[j].x,
×
260
                            shape->line[0].point[j].y);
×
261
        } else {
262
          OGR_G_SetPoint(hPoint, 0, shape->line[0].point[j].x,
×
263
                         shape->line[0].point[j].y, shape->line[0].point[j].z);
×
264
        }
265

266
        OGR_G_AddGeometryDirectly(hGeom, hPoint);
×
267
      }
268
    } else {
269
      if (shape->numlines > 1)
68✔
270
        hMP = OGR_G_CreateGeometry(wkbMultiPoint);
×
271

272
      for (j = 0; j < shape->numlines; j++) {
136✔
273
        if (shape->line[j].numpoints != 1) {
68✔
274
          msSetError(MS_MISCERR, "Failed on odd point geometry.",
×
275
                     "msOGRWriteShape()");
276
          return MS_FAILURE;
×
277
        }
278

279
        hGeom = OGR_G_CreateGeometry(wkbPoint);
68✔
280
        if (bWant2DOutput) {
68✔
281
          OGR_G_SetPoint_2D(hGeom, 0, shape->line[j].point[0].x,
68✔
282
                            shape->line[j].point[0].y);
68✔
283
        } else {
284
          OGR_G_SetPoint(hGeom, 0, shape->line[j].point[0].x,
×
285
                         shape->line[j].point[0].y, shape->line[j].point[0].z);
×
286
        }
287

288
        if (hMP != NULL) {
68✔
289
          OGR_G_AddGeometryDirectly(hMP, hGeom);
×
290
        }
291
      }
292

293
      if (hMP != NULL)
68✔
294
        hGeom = hMP;
295
    }
296
  }
297

298
  /* -------------------------------------------------------------------- */
299
  /*      Transform line geometry.                                        */
300
  /* -------------------------------------------------------------------- */
301
  else if (shape->type == MS_SHAPE_LINE) {
90✔
302
    OGRGeometryH hML = NULL;
303
    int j;
304

305
    if (shape->numlines > 1)
12✔
306
      hML = OGR_G_CreateGeometry(wkbMultiLineString);
×
307

308
    for (j = 0; j < shape->numlines; j++) {
24✔
309

310
      if (shape->line[j].numpoints < 2) {
12✔
311
        msSetError(MS_MISCERR, "Failed on odd line geometry.",
×
312
                   "msOGRWriteShape()");
313
        return MS_FAILURE;
×
314
      }
315

316
      hGeom = OGR_G_CreateGeometry(wkbLineString);
12✔
317

318
      msOGRSetPoints(hGeom, &(shape->line[j]), bWant2DOutput);
12✔
319

320
      if (hML != NULL) {
12✔
321
        OGR_G_AddGeometryDirectly(hML, hGeom);
×
322
        hGeom = hML;
323
      }
324
    }
325
  }
326

327
  /* -------------------------------------------------------------------- */
328
  /*      Transform polygon geometry.                                     */
329
  /* -------------------------------------------------------------------- */
330
  else if (shape->type == MS_SHAPE_POLYGON) {
78✔
331
    int iRing, iOuter;
332
    int *outer_flags;
333
    OGRGeometryH hMP = NULL;
334

335
    outer_flags = msGetOuterList(shape);
78✔
336

337
    for (iOuter = 0; iOuter < shape->numlines; iOuter++) {
159✔
338
      int *inner_flags;
339
      OGRGeometryH hRing;
340

341
      if (!outer_flags[iOuter])
81✔
342
        continue;
2✔
343

344
      if (hGeom != nullptr) {
79✔
345
        assert(hMP == nullptr);
346
        hMP = OGR_G_CreateGeometry(wkbMultiPolygon);
1✔
347
        OGR_G_AddGeometryDirectly(hMP, hGeom);
1✔
348
      }
349
      hGeom = OGR_G_CreateGeometry(wkbPolygon);
79✔
350

351
      /* handle outer ring */
352

353
      hRing = OGR_G_CreateGeometry(wkbLinearRing);
79✔
354

355
      msOGRSetPoints(hRing, &(shape->line[iOuter]), bWant2DOutput);
79✔
356

357
      OGR_G_AddGeometryDirectly(hGeom, hRing);
79✔
358

359
      /* handle inner rings (holes) */
360
      inner_flags = msGetInnerList(shape, iOuter, outer_flags);
79✔
361

362
      for (iRing = 0; iRing < shape->numlines; iRing++) {
163✔
363
        if (!inner_flags[iRing])
84✔
364
          continue;
82✔
365

366
        hRing = OGR_G_CreateGeometry(wkbLinearRing);
2✔
367

368
        msOGRSetPoints(hRing, &(shape->line[iRing]), bWant2DOutput);
2✔
369

370
        OGR_G_AddGeometryDirectly(hGeom, hRing);
2✔
371
      }
372

373
      free(inner_flags);
79✔
374

375
      if (hMP) {
79✔
376
        OGR_G_AddGeometryDirectly(hMP, hGeom);
1✔
377
        hGeom = nullptr;
378
      }
379
    }
380

381
    free(outer_flags);
78✔
382

383
    if (hMP != nullptr) {
78✔
384
      assert(hGeom == nullptr);
385
      hGeom = hMP;
386
    }
387
  }
388

389
  /* -------------------------------------------------------------------- */
390
  /*      Consider trying to force the geometry to a new type if it       */
391
  /*      doesn't match the layer.                                        */
392
  /* -------------------------------------------------------------------- */
393
  if (hGeom != NULL) {
157✔
394
    OGRwkbGeometryType eFlattenFeatureGType =
395
        wkbFlatten(OGR_G_GetGeometryType(hGeom));
158✔
396

397
    if (eFlattenFeatureGType != eFlattenLayerGType) {
158✔
398
      if (eFlattenLayerGType == wkbPolygon && geomTypeForced)
66✔
399
        hGeom = OGR_G_ForceToPolygon(hGeom);
×
400

401
      else if (eFlattenLayerGType == wkbMultiPolygon)
66✔
402
        hGeom = OGR_G_ForceToMultiPolygon(hGeom);
×
403

404
      else if (eFlattenLayerGType == wkbMultiPoint)
66✔
405
        hGeom = OGR_G_ForceToMultiPoint(hGeom);
×
406

407
      else if (eFlattenLayerGType == wkbMultiLineString)
66✔
408
        hGeom = OGR_G_ForceToMultiLineString(hGeom);
×
409
    }
410
  }
411

412
  /* -------------------------------------------------------------------- */
413
  /*      Consider flattening the geometry to 2D if we want 2D            */
414
  /*      output.                                                         */
415
  /*      Note: this shouldn't be called in recent OGR versions where     */
416
  /*      OGR_G_SetPoint_2D is properly honoured.                         */
417
  /* -------------------------------------------------------------------- */
418

419
  if (bWant2DOutput && hGeom != NULL) {
158✔
420
    OGRwkbGeometryType eFeatureGType = OGR_G_GetGeometryType(hGeom);
158✔
421
    if (eFeatureGType != wkbFlatten(eFeatureGType))
158✔
422
      OGR_G_FlattenTo2D(hGeom);
×
423
  }
424

425
  /* -------------------------------------------------------------------- */
426
  /*      Create the feature, and attach the geometry.                    */
427
  /* -------------------------------------------------------------------- */
428
  hFeat = OGR_F_Create(hLayerDefn);
158✔
429

430
  OGR_F_SetGeometryDirectly(hFeat, hGeom);
158✔
431

432
  /* -------------------------------------------------------------------- */
433
  /*      Set attributes.                                                 */
434
  /* -------------------------------------------------------------------- */
435
  out_field = nFirstOGRFieldIndex;
436
  for (i = 0; i < item_list->numitems; i++) {
2,198✔
437
    gmlItemObj *item = item_list->items + i;
2,040✔
438

439
    if (pszFeatureid && !strcmp(pszFeatureid, item->name)) {
2,040✔
440
      char *endptr;
441
      long feature_id = strtol(shape->values[i], &endptr, 10);
48✔
442
      if (endptr && *endptr == 0) {
48✔
443
        /* only set the featureid if it is numeric */
444
        OGR_F_SetFID(hFeat, feature_id);
48✔
445
      }
446
    }
447

448
    if (!item->visible)
2,040✔
449
      continue;
1,549✔
450

451
    /* Avoid setting empty strings for numeric fields, so that OGR */
452
    /* doesn't take them as 0. (#4633) */
453
    if (shape->values[i][0] == '\0') {
491✔
454
      OGRFieldDefnH hFieldDefn = OGR_FD_GetFieldDefn(hLayerDefn, out_field);
27✔
455
      OGRFieldType eFieldType = OGR_Fld_GetType(hFieldDefn);
27✔
456
      if (eFieldType == OFTInteger || eFieldType == OFTReal ||
27✔
457
          eFieldType == OFTInteger64) {
458
        out_field++;
2✔
459
        continue;
2✔
460
      }
461
    }
462

463
    const char *pszValue = shape->values[i];
489✔
464
#if GDAL_VERSION_MAJOR == 3 && GDAL_VERSION_MINOR < 7
465
    // Boolean true and false values are handled in GDAL 3.7+
466
    // otherwise any string values revert to false
467
    if (strcmp(pszValue, "true") == 0) {
468
      OGRFieldDefnH hFieldDefn = OGR_FD_GetFieldDefn(hLayerDefn, out_field);
469
      OGRFieldSubType eFieldSubType = OGR_Fld_GetSubType(hFieldDefn);
470
      if (eFieldSubType == OFSTBoolean) {
471
        pszValue = "1";
472
      }
473
    }
474

475
    if (strcmp(pszValue, "false") == 0) {
476
      OGRFieldDefnH hFieldDefn = OGR_FD_GetFieldDefn(hLayerDefn, out_field);
477
      OGRFieldSubType eFieldSubType = OGR_Fld_GetSubType(hFieldDefn);
478
      if (eFieldSubType == OFSTBoolean) {
479
        pszValue = "0";
480
      }
481
    }
482
#endif
483

484
    OGR_F_SetFieldString(hFeat, out_field++, pszValue);
489✔
485
  }
486

487
  /* -------------------------------------------------------------------- */
488
  /*      Write out and cleanup.                                          */
489
  /* -------------------------------------------------------------------- */
490
  eErr = OGR_L_CreateFeature(hOGRLayer, hFeat);
158✔
491

492
  OGR_F_Destroy(hFeat);
158✔
493

494
  if (eErr != OGRERR_NONE) {
158✔
495
    msSetError(MS_OGRERR, "Attempt to write feature failed (code=%d):\n%s",
×
496
               "msOGRWriteShape()", (int)eErr, CPLGetLastErrorMsg());
497
  }
498

499
  if (eErr == OGRERR_NONE)
500
    return MS_SUCCESS;
501
  else
502
    return MS_FAILURE;
×
503
}
504

505
/************************************************************************/
506
/*                        msOGRStdoutWriteFunction()                    */
507
/************************************************************************/
508

509
/* Used by /vsistdout/ */
510
static size_t msOGRStdoutWriteFunction(const void *ptr, size_t size,
167✔
511
                                       size_t nmemb, FILE *stream) {
512
  msIOContext *ioctx = (msIOContext *)stream;
513
  return msIO_contextWrite(ioctx, ptr, size * nmemb) / size;
167✔
514
}
515

516
/************************************************************************/
517
/*                      msOGROutputGetAdditionalFiles()                  */
518
/*                                                                      */
519
/*  Collect additional files specified in                               */
520
/*  wfs/ows_additional_files_in_output of WEB.METADATA and LAYER.METADATA */
521
/************************************************************************/
522

523
/* Result to be freed with CSLDestroy() */
524
static char **msOGROutputGetAdditionalFiles(mapObj *map) {
12✔
525
  int i;
526
  hashTableObj *hSetAdditionalFiles;
527
  char **papszFiles = NULL;
528

529
  hSetAdditionalFiles = msCreateHashTable();
12✔
530

531
  for (i = -1; i < map->numlayers; i++) {
81✔
532
    const char *value;
533
    if (i < 0) {
69✔
534
      value = msOWSLookupMetadata(&(map->web.metadata), "FO",
12✔
535
                                  "additional_files_in_output");
536
    } else {
537
      layerObj *layer = GET_LAYER(map, i);
57✔
538
      if (!layer->resultcache || layer->resultcache->numresults == 0)
57✔
539
        continue;
43✔
540
      value = msOWSLookupMetadata(&(layer->metadata), "FO",
14✔
541
                                  "additional_files_in_output");
542
    }
543

544
    if (value != NULL) {
26✔
545
      char **papszList = CSLTokenizeString2(value, ",", CSLT_HONOURSTRINGS);
3✔
546
      char **papszListIter = papszList;
547
      while (papszListIter && *papszListIter) {
15✔
548
        const char *file = *papszListIter;
549
        VSIStatBufL sStat;
550

551
        if (strncmp(file, "http://", strlen("http://")) == 0 ||
12✔
552
            strncmp(file, "https://", strlen("https://")) == 0) {
12✔
553
          /* Remote file ? We will use /vsicurl_streaming/ to read it */
554
          if (msLookupHashTable(hSetAdditionalFiles, file) == NULL) {
×
555
            msInsertHashTable(hSetAdditionalFiles, file, "YES");
×
556
            papszFiles = CSLAddString(
×
557
                papszFiles, CPLSPrintf("/vsicurl_streaming/%s", file));
558
          }
559
        } else {
560
          int nLen = (int)strlen(file);
12✔
561
          char filename[MS_MAXPATHLEN];
562

563
          if (CPLIsFilenameRelative(file)) {
12✔
564
            if (!map->shapepath)
12✔
565
              msTryBuildPath(filename, map->mappath, file);
×
566
            else
567
              msTryBuildPath3(filename, map->mappath, map->shapepath, file);
12✔
568
          } else
569
            strlcpy(filename, file, MS_MAXPATHLEN);
570

571
          if (nLen > 2 && (strcmp(file + nLen - 1, "/") == 0 ||
12✔
572
                           strcmp(file + nLen - 2, "/*") == 0)) {
10✔
573
            *strrchr(filename, '/') = '\0';
2✔
574
          } else if (nLen > 2 && (strcmp(file + nLen - 1, "\\") == 0 ||
10✔
575
                                  strcmp(file + nLen - 2, "\\*") == 0)) {
10✔
576
            *strrchr(filename, '\\') = '\0';
×
577
          }
578

579
          if (msLookupHashTable(hSetAdditionalFiles, filename) == NULL) {
12✔
580
            msInsertHashTable(hSetAdditionalFiles, filename, "YES");
8✔
581
            if (VSIStatL(filename, &sStat) == 0) {
8✔
582
              if (VSI_ISDIR(sStat.st_mode)) {
7✔
583
                char **papszDirContent = msOGRRecursiveFileList(filename);
2✔
584
                papszFiles = msCSLConcatenate(papszFiles, papszDirContent);
585
                CSLDestroy(papszDirContent);
2✔
586
              } else {
587
                papszFiles = CSLAddString(papszFiles, filename);
5✔
588
              }
589
            } else {
590
              msDebug("File %s does not exist.\n", filename);
1✔
591
            }
592
          }
593
        }
594

595
        papszListIter++;
12✔
596
      }
597
      CSLDestroy(papszList);
3✔
598
    }
599
  }
600

601
  msFreeHashTable(hSetAdditionalFiles);
12✔
602

603
  return papszFiles;
12✔
604
}
605

606
/************************************************************************/
607
/*                        msOGRWriteFromQuery()                         */
608
/************************************************************************/
609

610
int msOGRWriteFromQuery(mapObj *map, outputFormatObj *format, int sendheaders)
40✔
611

612
{
613
  /* -------------------------------------------------------------------- */
614
  /*      Variable declarations.                                          */
615
  /* -------------------------------------------------------------------- */
616
  OGRSFDriverH hDriver;
617
  OGRDataSourceH hDS;
618
  const char *storage;
619
  const char *fo_filename;
620
  const char *form;
621
  char datasource_name[MS_MAXPATHLEN];
622
  char base_dir[MS_MAXPATHLEN];
623
  char *request_dir = NULL;
624
  char **ds_options = NULL;
625
  char **layer_options = NULL;
626
  char **file_list = NULL;
627
  int iLayer, i;
628
  int bDataSourceNameIsRequestDir = FALSE;
629
  int bUseFeatureId = MS_FALSE;
630
  const char *pszMatchingFeatures;
631
  int nMatchingFeatures = -1;
632
  const char *pszFormatName = format->driver + 4;
40✔
633

634
  pszMatchingFeatures =
635
      msGetOutputFormatOption(format, "_matching_features_", "");
40✔
636
  if (pszMatchingFeatures[0] != '\0')
40✔
637
    nMatchingFeatures = atoi(pszMatchingFeatures);
638

639
  /* -------------------------------------------------------------------- */
640
  /*      Fetch the output format driver.                                 */
641
  /* -------------------------------------------------------------------- */
642
  msOGRInitialize();
40✔
643

644
  hDriver = OGRGetDriverByName(pszFormatName);
40✔
645
  if (hDriver == NULL) {
40✔
646
    msSetError(MS_MISCERR, "No OGR driver named `%s' available.",
×
647
               "msOGRWriteFromQuery()", pszFormatName);
648
    return MS_FAILURE;
×
649
  }
650

651
  /* -------------------------------------------------------------------- */
652
  /*      Capture datasource and layer creation options.                  */
653
  /* -------------------------------------------------------------------- */
654
  for (i = 0; i < format->numformatoptions; i++) {
212✔
655
    if (strncasecmp(format->formatoptions[i], "LCO:", 4) == 0)
172✔
656
      layer_options = CSLAddString(layer_options, format->formatoptions[i] + 4);
30✔
657
    if (strncasecmp(format->formatoptions[i], "DSCO:", 5) == 0)
172✔
658
      ds_options = CSLAddString(ds_options, format->formatoptions[i] + 5);
4✔
659
  }
660
  if (EQUAL(pszFormatName, "GeoJSON") && nMatchingFeatures >= 0) {
40✔
661
    const char *pszNativeData =
662
        CSLFetchNameValueDef(layer_options, "NATIVE_DATA", "{}");
4✔
663
    if (pszNativeData[strlen(pszNativeData) - 1] == '}') {
4✔
664
      std::string tmpl(pszNativeData);
4✔
665
      tmpl.resize(tmpl.size() - 1);
4✔
666
      if (strlen(pszNativeData) > 2)
4✔
667
        tmpl += ',';
668
      tmpl += "\"numberMatched\":";
669
      tmpl += std::to_string(nMatchingFeatures);
8✔
670
      tmpl += '}';
671
      layer_options = CSLSetNameValue(layer_options, "NATIVE_MEDIA_TYPE",
4✔
672
                                      "application/vnd.geo+json");
673
      layer_options =
674
          CSLSetNameValue(layer_options, "NATIVE_DATA", tmpl.c_str());
4✔
675
    }
676
  }
677
  if (!strcasecmp("true",
40✔
678
                  msGetOutputFormatOption(format, "USE_FEATUREID", "false"))) {
679
    bUseFeatureId = MS_TRUE;
680
  }
681

682
  /* ==================================================================== */
683
  /*      Determine the output datasource name to use.                    */
684
  /* ==================================================================== */
685
  storage = msGetOutputFormatOption(format, "STORAGE", "filesystem");
40✔
686
  if (EQUAL(storage, "stream") && !msIO_isStdContext()) {
40✔
687
    msIOContext *ioctx = msIO_getHandler(stdout);
5✔
688
    if (ioctx != NULL)
5✔
689
      VSIStdoutSetRedirection(msOGRStdoutWriteFunction, (FILE *)ioctx);
5✔
690
    else
691
      /* bug #4858, streaming output won't work if standard output has been
692
       * redirected, we switch to memory output in this case
693
       */
694
      storage = "memory";
695
  }
696

697
  /* -------------------------------------------------------------------- */
698
  /*      Where are we putting stuff?                                     */
699
  /* -------------------------------------------------------------------- */
700
  if (EQUAL(storage, "filesystem")) {
40✔
701
    base_dir[0] = '\0';
10✔
702
  } else if (EQUAL(storage, "memory")) {
30✔
703
    strcpy(base_dir, "/vsimem/ogr_out/");
704
  } else if (EQUAL(storage, "stream")) {
5✔
705
    /* handled later */
706
  } else {
707
    msSetError(MS_MISCERR, "STORAGE=%s value not supported.",
×
708
               "msOGRWriteFromQuery()", storage);
709
    CSLDestroy(layer_options);
×
710
    CSLDestroy(ds_options);
×
711
    return MS_FAILURE;
×
712
  }
713

714
  /* -------------------------------------------------------------------- */
715
  /*      Create a subdirectory to handle this request.                   */
716
  /* -------------------------------------------------------------------- */
717
  if (!EQUAL(storage, "stream")) {
40✔
718
    const char *dir_to_create;
719
    if (strlen(base_dir) > 0)
35✔
720
      request_dir = msTmpFile(map, NULL, base_dir, "");
25✔
721
    else
722
      request_dir = msTmpFile(map, NULL, NULL, "");
10✔
723

724
    if (request_dir[strlen(request_dir) - 1] == '.')
35✔
725
      request_dir[strlen(request_dir) - 1] = '\0';
35✔
726

727
    dir_to_create = request_dir;
728
    /* Workaround issue in GDAL versions released at this time :
729
     * GDAL issue fixed per https://trac.osgeo.org/gdal/ticket/6991 */
730
    if (EQUAL(storage, "memory") &&
35✔
731
        EQUAL(format->driver + 4, "ESRI Shapefile")) {
25✔
732
      dir_to_create = base_dir;
733
    }
734

735
    if (VSIMkdir(dir_to_create, 0777) != 0) {
35✔
736
      msSetError(MS_MISCERR, "Attempt to create directory '%s' failed.",
×
737
                 "msOGRWriteFromQuery()", dir_to_create);
738
      msFree(request_dir);
×
739
      CSLDestroy(layer_options);
×
740
      CSLDestroy(ds_options);
×
741
      return MS_FAILURE;
×
742
    }
743
  }
744
  /*  else handled later */
745

746
  /* -------------------------------------------------------------------- */
747
  /*      Setup the full datasource name.                                 */
748
  /* -------------------------------------------------------------------- */
749
  form = msGetOutputFormatOption(format, "FORM", "zip");
40✔
750

751
  if (EQUAL(form, "zip"))
40✔
752
    fo_filename = msGetOutputFormatOption(format, "FILENAME", "result.zip");
×
753
  else
754
    fo_filename = msGetOutputFormatOption(format, "FILENAME", "result.dat");
40✔
755

756
  /* Validate that the filename does not contain any directory */
757
  /* information, which might lead to removal of unwanted files. (#4086) */
758
  if (strchr(fo_filename, '/') != NULL || strchr(fo_filename, ':') != NULL ||
40✔
759
      strchr(fo_filename, '\\') != NULL) {
760
    msSetError(MS_MISCERR,
1✔
761
               "Invalid value for FILENAME option. "
762
               "It must not contain any directory information.",
763
               "msOGRWriteFromQuery()");
764
    msFree(request_dir);
1✔
765
    CSLDestroy(layer_options);
1✔
766
    CSLDestroy(ds_options);
1✔
767
    return MS_FAILURE;
1✔
768
  }
769

770
  if (!EQUAL(storage, "stream")) {
39✔
771
    if (!msBuildPath(datasource_name, request_dir, fo_filename)) {
34✔
772
      msFree(request_dir);
×
773
      CSLDestroy(layer_options);
×
774
      CSLDestroy(ds_options);
×
775
      return MS_FAILURE;
×
776
    }
777

778
    if (EQUAL(form, "zip")) {
34✔
779
      /* if generating a zip file, remove the zip extension for the internal */
780
      /* filename */
781
      if (EQUAL(CPLGetExtension(datasource_name), "zip")) {
×
782
        *strrchr(datasource_name, '.') = '\0';
×
783
      }
784

785
      /* and add .dat extension if user didn't provide another extension */
786
      if (EQUAL(CPLGetExtension(datasource_name), "")) {
×
787
        strlcat(datasource_name, ".dat", sizeof(datasource_name));
788
      }
789
    }
790

791
    /* Shapefile and MapInfo driver only properly work with multiple layers */
792
    /* if the output dataset name is a directory */
793
    if (EQUAL(format->driver + 4, "ESRI Shapefile") ||
34✔
794
        EQUAL(format->driver + 4, "MapInfo File")) {
34✔
795
      bDataSourceNameIsRequestDir = TRUE;
796
      strcpy(datasource_name, request_dir);
797
    }
798
  } else
799
    strcpy(datasource_name, "/vsistdout/");
800

801
  msFree(request_dir);
39✔
802
  request_dir = NULL;
803

804
  /* -------------------------------------------------------------------- */
805
  /*      Emit content type headers for stream output now.                */
806
  /* -------------------------------------------------------------------- */
807
  if (EQUAL(storage, "stream")) {
39✔
808
    if (sendheaders && format->mimetype) {
5✔
809
      msIO_setHeader("Content-Type", "%s", format->mimetype);
5✔
810
      msIO_sendHeaders();
5✔
811
    } else
812
      msIO_fprintf(stdout, "%c", 10);
×
813
  }
814

815
  /* ==================================================================== */
816
  /*      Create the datasource.                                          */
817
  /* ==================================================================== */
818
  hDS = OGR_Dr_CreateDataSource(hDriver, datasource_name, ds_options);
39✔
819
  CSLDestroy(ds_options);
39✔
820

821
  if (hDS == NULL) {
39✔
822
    msOGRCleanupDS(datasource_name);
×
823
    msSetError(MS_MISCERR,
×
824
               "OGR CreateDataSource failed for '%s' with driver '%s'.",
825
               "msOGRWriteFromQuery()", datasource_name, format->driver + 4);
×
826
    CSLDestroy(layer_options);
×
827
    return MS_FAILURE;
×
828
  }
829

830
  /* ==================================================================== */
831
  /*      Process each layer with a resultset.                            */
832
  /* ==================================================================== */
833
  for (iLayer = 0; iLayer < map->numlayers; iLayer++) {
284✔
834
    int status = 0;
835
    layerObj *layer = GET_LAYER(map, iLayer);
245✔
836
    shapeObj resultshape;
837
    OGRLayerH hOGRLayer;
838
    OGRwkbGeometryType eGeomType;
839
    OGRSpatialReferenceH srs = NULL;
840
    gmlItemListObj *item_list = NULL;
841
    const char *value;
842
    char *pszWKT;
843
    int nFirstOGRFieldIndex = -1;
844
    const char *pszFeatureid = NULL;
845

846
    if (!layer->resultcache)
245✔
847
      continue;
204✔
848

849
    /* -------------------------------------------------------------------- */
850
    /*      Will we need to reproject?                                      */
851
    /* -------------------------------------------------------------------- */
852
    if (layer->transform == MS_TRUE)
41✔
853
      layer->project =
41✔
854
          msProjectionsDiffer(&(layer->projection), &(layer->map->projection));
41✔
855

856
    /* -------------------------------------------------------------------- */
857
    /*      Establish the geometry type to use for the created layer.       */
858
    /*      First we consult the wfs_geomtype field and fallback to         */
859
    /*      deriving something from the type of the mapserver layer.        */
860
    /* -------------------------------------------------------------------- */
861
    value = msOWSLookupMetadata(&(layer->metadata), "FOG", "geomtype");
41✔
862
    bool geomTypeForced = true;
863
    if (value == NULL) {
41✔
864
      geomTypeForced = false;
865
      if (layer->type == MS_LAYER_POINT)
39✔
866
        value = "Point";
867
      else if (layer->type == MS_LAYER_LINE)
868
        value = "LineString";
869
      else if (layer->type == MS_LAYER_POLYGON)
870
        value = "Polygon";
871
      else
872
        value = "Geometry";
873
    }
874

875
    if (bUseFeatureId)
41✔
876
      pszFeatureid =
877
          msOWSLookupMetadata(&(layer->metadata), "FOG", "featureid");
3✔
878

879
    if (strcasecmp(value, "Point") == 0)
41✔
880
      eGeomType = wkbPoint;
881
    else if (strcasecmp(value, "LineString") == 0)
29✔
882
      eGeomType = wkbLineString;
883
    else if (strcasecmp(value, "Polygon") == 0)
19✔
884
      eGeomType = wkbPolygon;
885
    else if (strcasecmp(value, "MultiPoint") == 0)
3✔
886
      eGeomType = wkbMultiPoint;
887
    else if (strcasecmp(value, "MultiLineString") == 0)
3✔
888
      eGeomType = wkbMultiLineString;
889
    else if (strcasecmp(value, "MultiPolygon") == 0)
3✔
890
      eGeomType = wkbMultiPolygon;
891
    else if (strcasecmp(value, "GeometryCollection") == 0)
3✔
892
      eGeomType = wkbGeometryCollection;
893
    else if (strcasecmp(value, "Point25D") == 0)
3✔
894
      eGeomType = wkbPoint25D;
895
    else if (strcasecmp(value, "LineString25D") == 0)
3✔
896
      eGeomType = wkbLineString25D;
897
    else if (strcasecmp(value, "Polygon25D") == 0)
3✔
898
      eGeomType = wkbPolygon25D;
899
    else if (strcasecmp(value, "MultiPoint25D") == 0)
3✔
900
      eGeomType = wkbMultiPoint25D;
901
    else if (strcasecmp(value, "MultiLineString25D") == 0)
3✔
902
      eGeomType = wkbMultiLineString25D;
903
    else if (strcasecmp(value, "MultiPolygon25D") == 0)
3✔
904
      eGeomType = wkbMultiPolygon25D;
905
    else if (strcasecmp(value, "GeometryCollection25D") == 0)
3✔
906
      eGeomType = wkbGeometryCollection25D;
907
    else if (strcasecmp(value, "Unknown") == 0 ||
3✔
908
             strcasecmp(value, "Geometry") == 0)
3✔
909
      eGeomType = wkbUnknown;
910
    else if (strcasecmp(value, "None") == 0)
×
911
      eGeomType = wkbNone;
912
    else
913
      eGeomType = wkbUnknown;
914

915
    /* -------------------------------------------------------------------- */
916
    /*      Create a spatial reference.                                     */
917
    /* -------------------------------------------------------------------- */
918
    pszWKT = msProjectionObj2OGCWKT(&(map->projection));
41✔
919
    if (pszWKT != NULL) {
41✔
920
      srs = OSRNewSpatialReference(pszWKT);
26✔
921
      msFree(pszWKT);
26✔
922
    }
923

924
    /* -------------------------------------------------------------------- */
925
    /*      Create the corresponding OGR Layer.                             */
926
    /* -------------------------------------------------------------------- */
927
    hOGRLayer =
928
        OGR_DS_CreateLayer(hDS, layer->name, srs, eGeomType, layer_options);
41✔
929
    if (hOGRLayer == NULL) {
41✔
930
      OGR_DS_Destroy(hDS);
×
931
      msOGRCleanupDS(datasource_name);
×
932
      msSetError(
×
933
          MS_MISCERR,
934
          "OGR OGR_DS_CreateLayer failed for layer '%s' with driver '%s'.",
935
          "msOGRWriteFromQuery()", layer->name, format->driver + 4);
×
936
      CSLDestroy(layer_options);
×
937
      return MS_FAILURE;
×
938
    }
939

940
    if (srs != NULL)
41✔
941
      OSRRelease(srs);
26✔
942

943
    /* -------------------------------------------------------------------- */
944
    /*      Create appropriate attributes on this layer.                    */
945
    /* -------------------------------------------------------------------- */
946
    item_list = msGMLGetItems(layer, "G");
41✔
947
    assert(item_list->numitems == layer->numitems);
948

949
    for (i = 0; i < layer->numitems; i++) {
469✔
950
      OGRFieldDefnH hFldDefn;
951
      OGRErr eErr;
952
      const char *name;
953
      gmlItemObj *item = item_list->items + i;
428✔
954
      OGRFieldType eType;
955
      OGRFieldSubType sType = OGRFieldSubType::OFSTNone;
956

957
      if (!item->visible)
428✔
958
        continue;
247✔
959

960
      if (item->alias)
181✔
961
        name = item->alias;
962
      else
963
        name = item->name;
174✔
964

965
      if (item->type == NULL)
181✔
966
        eType = OFTString;
967
      else if (EQUAL(item->type, "Integer"))
138✔
968
        eType = OFTInteger;
969
      else if (EQUAL(item->type, "Long"))
65✔
970
        eType = OFTInteger64;
971
      else if (EQUAL(item->type, "Real"))
64✔
972
        eType = OFTReal;
973
      else if (EQUAL(item->type, "Character"))
51✔
974
        eType = OFTString;
975
      else if (EQUAL(item->type, "Date"))
9✔
976
        eType = OFTDate;
977
      else if (EQUAL(item->type, "Time"))
7✔
978
        eType = OFTTime;
979
      else if (EQUAL(item->type, "DateTime"))
6✔
980
        eType = OFTDateTime;
981
      else if (EQUAL(item->type, "Boolean")) {
3✔
982
        eType = OFTInteger;
983
        sType = OFSTBoolean;
984
      } else
985
        eType = OFTString;
986

987
      hFldDefn = OGR_Fld_Create(name, eType);
181✔
988
      if (sType != OGRFieldSubType::OFSTNone) {
181✔
989
        OGR_Fld_SetSubType(hFldDefn, sType);
3✔
990
      }
991
      if (item->width != 0)
181✔
992
        OGR_Fld_SetWidth(hFldDefn, item->width);
112✔
993
      if (item->precision != 0)
181✔
994
        OGR_Fld_SetPrecision(hFldDefn, item->precision);
9✔
995

996
      eErr = OGR_L_CreateField(hOGRLayer, hFldDefn, TRUE);
181✔
997
      OGR_Fld_Destroy(hFldDefn);
181✔
998

999
      if (eErr != OGRERR_NONE) {
181✔
1000
        msSetError(MS_OGRERR,
×
1001
                   "Failed to create field '%s' in output feature schema:\n%s",
1002
                   "msOGRWriteFromQuery()", layer->items[i],
×
1003
                   CPLGetLastErrorMsg());
1004

1005
        OGR_DS_Destroy(hDS);
×
1006
        msOGRCleanupDS(datasource_name);
×
1007
        msGMLFreeItems(item_list);
×
1008
        CSLDestroy(layer_options);
×
1009
        return MS_FAILURE;
×
1010
      }
1011

1012
      /* The index of the first field we create is not necessarily 0 */
1013
      if (nFirstOGRFieldIndex < 0)
181✔
1014
        nFirstOGRFieldIndex =
37✔
1015
            OGR_FD_GetFieldCount(OGR_L_GetLayerDefn(hOGRLayer)) - 1;
37✔
1016
    }
1017

1018
    /* -------------------------------------------------------------------- */
1019
    /*      Setup joins if needed.  This is likely untested.                */
1020
    /* -------------------------------------------------------------------- */
1021
    if (layer->numjoins > 0) {
41✔
1022
      int j;
1023
      for (j = 0; j < layer->numjoins; j++) {
×
1024
        status = msJoinConnect(layer, &(layer->joins[j]));
×
1025
        if (status != MS_SUCCESS) {
×
1026
          OGR_DS_Destroy(hDS);
×
1027
          msOGRCleanupDS(datasource_name);
×
1028
          msGMLFreeItems(item_list);
×
1029
          CSLDestroy(layer_options);
×
1030
          return status;
×
1031
        }
1032
      }
1033
    }
1034

1035
    msInitShape(&resultshape);
41✔
1036

1037
    /* -------------------------------------------------------------------- */
1038
    /*      Loop over all the shapes in the resultcache.                    */
1039
    /* -------------------------------------------------------------------- */
1040
    for (i = 0; i < layer->resultcache->numresults; i++) {
199✔
1041

1042
      msFreeShape(&resultshape); /* init too */
158✔
1043

1044
      /*
1045
      ** Read the shape.
1046
      */
1047
      bool shapeFromCache = false;
1048
      if (layer->resultcache->results[i].shape) {
158✔
1049
        /* msDebug("Using cached shape %ld\n",
1050
         * layer->resultcache->results[i].shapeindex); */
1051
        shapeFromCache = true;
1052
        status =
1053
            msCopyShape(layer->resultcache->results[i].shape, &resultshape);
9✔
1054
      } else {
1055
        status = msLayerGetShape(layer, &resultshape,
149✔
1056
                                 &(layer->resultcache->results[i]));
1057
      }
1058

1059
      if (status != MS_SUCCESS) {
158✔
1060
        OGR_DS_Destroy(hDS);
×
1061
        msOGRCleanupDS(datasource_name);
×
1062
        msGMLFreeItems(item_list);
×
1063
        msFreeShape(&resultshape);
×
1064
        CSLDestroy(layer_options);
×
1065
        return status;
×
1066
      }
1067

1068
      /*
1069
      ** Perform classification, and some annotation related magic.
1070
      */
1071
      resultshape.classindex =
158✔
1072
          msShapeGetClass(layer, map, &resultshape, NULL, -1);
158✔
1073

1074
      if (resultshape.classindex >= 0 &&
158✔
1075
          (layer->_class[resultshape.classindex]->text.string ||
46✔
1076
           layer->labelitem) &&
46✔
1077
          layer->_class[resultshape.classindex]->numlabels > 0 &&
×
1078
          layer->_class[resultshape.classindex]->labels[0]->size != -1) {
×
1079
        resultshape.text = msShapeGetLabelAnnotation(
×
1080
            layer, &resultshape,
1081
            layer->_class[resultshape.classindex]->labels[0]);
1082
      }
1083

1084
      /*
1085
      ** prepare any necessary JOINs here (one-to-one only)
1086
      */
1087
      if (layer->numjoins > 0) {
158✔
1088
        int j;
1089

1090
        for (j = 0; j < layer->numjoins; j++) {
×
1091
          if (layer->joins[j].type == MS_JOIN_ONE_TO_ONE) {
×
1092
            msJoinPrepare(&(layer->joins[j]), &resultshape);
×
1093
            msJoinNext(&(layer->joins[j])); /* fetch the first row */
×
1094
          }
1095
        }
1096
      }
1097

1098
      if (layer->project && resultshape.type != MS_SHAPE_NULL &&
158✔
1099
          shapeFromCache != true) {
1100
        reprojectionObj *reprojector =
1101
            msLayerGetReprojectorToMap(layer, layer->map);
24✔
1102
        if (reprojector)
24✔
1103
          status = msProjectShapeEx(reprojector, &resultshape);
24✔
1104
        else
1105
          status = MS_FAILURE;
1106
      }
1107

1108
      /*
1109
      ** Write out the feature to OGR.
1110
      */
1111

1112
      if (status == MS_SUCCESS)
158✔
1113
        status =
1114
            msOGRWriteShape(hOGRLayer, &resultshape, item_list,
158✔
1115
                            nFirstOGRFieldIndex, pszFeatureid, geomTypeForced);
1116

1117
      if (status != MS_SUCCESS) {
158✔
1118
        OGR_DS_Destroy(hDS);
×
1119
        msOGRCleanupDS(datasource_name);
×
1120
        msGMLFreeItems(item_list);
×
1121
        msFreeShape(&resultshape);
×
1122
        CSLDestroy(layer_options);
×
1123
        return status;
×
1124
      }
1125
    }
1126

1127
    msGMLFreeItems(item_list);
41✔
1128
    msFreeShape(&resultshape); /* init too */
41✔
1129
  }
1130

1131
  /* -------------------------------------------------------------------- */
1132
  /*      Close the datasource.                                           */
1133
  /* -------------------------------------------------------------------- */
1134
  OGR_DS_Destroy(hDS);
39✔
1135

1136
  CSLDestroy(layer_options);
39✔
1137

1138
  /* -------------------------------------------------------------------- */
1139
  /*      Get list of resulting files.                                    */
1140
  /* -------------------------------------------------------------------- */
1141

1142
  if (EQUAL(form, "simple")) {
39✔
1143
    file_list = CSLAddString(NULL, datasource_name);
27✔
1144
  } else {
1145
    char datasource_path[MS_MAXPATHLEN];
1146

1147
    if (bDataSourceNameIsRequestDir)
12✔
1148
      file_list = msOGRRecursiveFileList(datasource_name);
3✔
1149
    else {
1150
      strncpy(datasource_path, CPLGetPath(datasource_name), MS_MAXPATHLEN - 1);
9✔
1151
      file_list = msOGRRecursiveFileList(datasource_path);
9✔
1152
    }
1153
  }
1154

1155
  /* -------------------------------------------------------------------- */
1156
  /*      If our "storage" is stream then the output has already been     */
1157
  /*      sent back to the client and we don't need to copy it now.       */
1158
  /* -------------------------------------------------------------------- */
1159
  if (EQUAL(storage, "stream")) {
39✔
1160
    /* already done */
1161
  }
1162

1163
  /* -------------------------------------------------------------------- */
1164
  /*      Handle case of simple file written to stdout.                   */
1165
  /* -------------------------------------------------------------------- */
1166
  else if (EQUAL(form, "simple")) {
34✔
1167
    char buffer[1024];
1168
    int bytes_read;
1169
    VSILFILE *fp;
1170
    const char *jsonp;
1171

1172
    jsonp = msGetOutputFormatOption(format, "JSONP", NULL);
22✔
1173
    if (sendheaders) {
22✔
1174
      if (!jsonp)
22✔
1175
        msIO_setHeader("Content-Disposition", "attachment; filename=%s",
22✔
1176
                       CPLGetFilename(file_list[0]));
1177
      if (format->mimetype)
22✔
1178
        msIO_setHeader("Content-Type", "%s", format->mimetype);
22✔
1179
      msIO_sendHeaders();
22✔
1180
    } else
1181
      msIO_fprintf(stdout, "%c", 10);
×
1182

1183
    fp = VSIFOpenL(file_list[0], "r");
22✔
1184
    if (fp == NULL) {
22✔
1185
      msSetError(MS_MISCERR, "Failed to open result file '%s'.",
×
1186
                 "msOGRWriteFromQuery()", file_list[0]);
1187
      msOGRCleanupDS(datasource_name);
×
1188
      return MS_FAILURE;
×
1189
    }
1190

1191
    if (jsonp != NULL)
22✔
1192
      msIO_fprintf(stdout, "%s(", jsonp);
×
1193

1194
    while ((bytes_read = VSIFReadL(buffer, 1, sizeof(buffer), fp)) > 0)
103✔
1195
      msIO_fwrite(buffer, 1, bytes_read, stdout);
81✔
1196
    VSIFCloseL(fp);
22✔
1197

1198
    if (jsonp != NULL)
22✔
1199
      msIO_fprintf(stdout, ");\n");
×
1200
  }
1201

1202
  /* -------------------------------------------------------------------- */
1203
  /*      Handle the case of a multi-part result.                         */
1204
  /* -------------------------------------------------------------------- */
1205
  else if (EQUAL(form, "multipart")) {
12✔
1206
    char **papszAdditionalFiles;
1207
    static const char *boundary = "xxOGRBoundaryxx";
1208
    msIO_setHeader("Content-Type", "multipart/mixed; boundary=%s", boundary);
12✔
1209
    msIO_sendHeaders();
12✔
1210
    msIO_fprintf(stdout, "--%s\r\n", boundary);
12✔
1211

1212
    papszAdditionalFiles = msOGROutputGetAdditionalFiles(map);
12✔
1213
    file_list = msCSLConcatenate(file_list, papszAdditionalFiles);
1214
    CSLDestroy(papszAdditionalFiles);
12✔
1215

1216
    for (i = 0; file_list != NULL && file_list[i] != NULL; i++) {
45✔
1217
      VSILFILE *fp;
1218
      int bytes_read;
1219
      char buffer[1024];
1220

1221
      if (sendheaders)
33✔
1222
        msIO_fprintf(stdout,
33✔
1223
                     "Content-Disposition: attachment; filename=%s\r\n"
1224
                     "Content-Type: application/binary\r\n"
1225
                     "Content-Transfer-Encoding: binary\r\n\r\n",
1226
                     CPLGetFilename(file_list[i]));
1227

1228
      fp = VSIFOpenL(file_list[i], "r");
33✔
1229
      if (fp == NULL) {
33✔
1230
        msSetError(MS_MISCERR, "Failed to open result file '%s'.",
×
1231
                   "msOGRWriteFromQuery()", file_list[0]);
1232
        msOGRCleanupDS(datasource_name);
×
1233
        return MS_FAILURE;
×
1234
      }
1235

1236
      while ((bytes_read = VSIFReadL(buffer, 1, sizeof(buffer), fp)) > 0)
750✔
1237
        msIO_fwrite(buffer, 1, bytes_read, stdout);
717✔
1238
      VSIFCloseL(fp);
33✔
1239

1240
      if (file_list[i + 1] == NULL)
33✔
1241
        msIO_fprintf(stdout, "\r\n--%s--\r\n", boundary);
12✔
1242
      else
1243
        msIO_fprintf(stdout, "\r\n--%s\r\n", boundary);
21✔
1244
    }
1245
  }
1246

1247
  /* -------------------------------------------------------------------- */
1248
  /*      Handle the case of a zip file result.                           */
1249
  /* -------------------------------------------------------------------- */
1250
  else if (EQUAL(form, "zip")) {
×
1251
    VSILFILE *fp;
1252
    char *zip_filename = msTmpFile(map, NULL, "/vsimem/ogrzip/", "zip");
×
1253
    void *hZip;
1254
    int bytes_read;
1255
    char buffer[1024];
1256
    char **papszAdditionalFiles;
1257

1258
    hZip = CPLCreateZip(zip_filename, NULL);
×
1259

1260
    papszAdditionalFiles = msOGROutputGetAdditionalFiles(map);
×
1261
    file_list = msCSLConcatenate(file_list, papszAdditionalFiles);
1262
    CSLDestroy(papszAdditionalFiles);
×
1263

1264
    for (i = 0; file_list != NULL && file_list[i] != NULL; i++) {
×
1265

1266
      const std::string osArchiveFilename(CPLGetFilename(file_list[i]));
×
1267
#if GDAL_VERSION_MAJOR > 3 ||                                                  \
1268
    (GDAL_VERSION_MAJOR == 3 && GDAL_VERSION_MINOR >= 7)
1269
      if (CPLAddFileInZip(hZip, osArchiveFilename.c_str(), file_list[i],
×
1270
                          nullptr, nullptr, nullptr, nullptr) != CE_None) {
1271
        msSetError(MS_MISCERR, "CPLAddFileInZip() failed for %s",
×
1272
                   "msOGRWriteFromQuery()", file_list[i]);
1273
        CPLCloseZip(hZip);
×
1274
        msOGRCleanupDS(datasource_name);
×
1275
        return MS_FAILURE;
1276
      }
1277
#else
1278
      if (CPLCreateFileInZip(hZip, osArchiveFilename.c_str(), NULL) !=
1279
          CE_None) {
1280
        msSetError(MS_MISCERR, "CPLWriteFileInZip() failed for %s",
1281
                   "msOGRWriteFromQuery()", file_list[i]);
1282
        CPLCloseZip(hZip);
1283
        msOGRCleanupDS(datasource_name);
1284
        return MS_FAILURE;
1285
      }
1286

1287
      fp = VSIFOpenL(file_list[i], "r");
1288
      if (fp == NULL) {
1289
        CPLCloseZip(hZip);
1290
        msSetError(MS_MISCERR, "Failed to open result file '%s'.",
1291
                   "msOGRWriteFromQuery()", file_list[i]);
1292
        msOGRCleanupDS(datasource_name);
1293
        return MS_FAILURE;
1294
      }
1295

1296
      while ((bytes_read = VSIFReadL(buffer, 1, sizeof(buffer), fp)) > 0) {
1297
        if (CPLWriteFileInZip(hZip, buffer, bytes_read) != CE_None) {
1298
          msSetError(MS_MISCERR, "CPLWriteFileInZip() failed for %s",
1299
                     "msOGRWriteFromQuery()", file_list[i]);
1300
          VSIFCloseL(fp);
1301
          CPLCloseFileInZip(hZip);
1302
          CPLCloseZip(hZip);
1303
          msOGRCleanupDS(datasource_name);
1304
          return MS_FAILURE;
1305
        }
1306
      }
1307
      VSIFCloseL(fp);
1308

1309
      CPLCloseFileInZip(hZip);
1310
#endif
1311
    }
1312
    CPLCloseZip(hZip);
×
1313

1314
    if (sendheaders) {
×
1315
      const char *zip_filename = fo_filename;
1316
      /* Make sure the filename is ended by .zip */
1317
      if (!EQUAL(CPLGetExtension(zip_filename), "zip") &&
×
1318
          !EQUAL(CPLGetExtension(zip_filename), "kmz"))
×
1319
        zip_filename = CPLFormFilename(NULL, fo_filename, "zip");
×
1320
      msIO_setHeader("Content-Disposition", "attachment; filename=%s",
×
1321
                     zip_filename);
1322
      msIO_setHeader("Content-Type", "application/zip");
×
1323
      msIO_sendHeaders();
×
1324
    }
1325

1326
    fp = VSIFOpenL(zip_filename, "r");
×
1327
    if (fp == NULL) {
×
1328
      msSetError(MS_MISCERR, "Failed to open zip file '%s'.",
×
1329
                 "msOGRWriteFromQuery()", file_list[0]);
1330
      msOGRCleanupDS(datasource_name);
×
1331
      return MS_FAILURE;
×
1332
    }
1333

1334
    while ((bytes_read = VSIFReadL(buffer, 1, sizeof(buffer), fp)) > 0)
×
1335
      msIO_fwrite(buffer, 1, bytes_read, stdout);
×
1336
    VSIFCloseL(fp);
×
1337

1338
    msFree(zip_filename);
×
1339
  }
1340

1341
  /* -------------------------------------------------------------------- */
1342
  /*      Handle illegal form value.                                      */
1343
  /* -------------------------------------------------------------------- */
1344
  else {
1345
    msSetError(MS_MISCERR, "Unsupported FORM=%s value.",
×
1346
               "msOGRWriteFromQuery()", form);
1347
    msOGRCleanupDS(datasource_name);
×
1348
    return MS_FAILURE;
×
1349
  }
1350

1351
  msOGRCleanupDS(datasource_name);
39✔
1352

1353
  CSLDestroy(file_list);
39✔
1354

1355
  return MS_SUCCESS;
1356
}
1357

1358
/************************************************************************/
1359
/*                     msPopulateRenderVTableOGR()                      */
1360
/************************************************************************/
1361

1362
int msPopulateRendererVTableOGR(rendererVTableObj *renderer) {
×
1363
  (void)renderer;
1364
  /* we aren't really a normal renderer so we leave everything default */
1365
  return MS_SUCCESS;
×
1366
}
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